removing the vendored optparse in favor of a pure-coffeescript optparse library

This commit is contained in:
Jeremy Ashkenas 2010-02-14 15:16:33 -05:00
parent 9de729e825
commit e77f4f61aa
11 changed files with 202 additions and 644 deletions

View File

@ -3,7 +3,7 @@
posix = require('posix');
path = require('path');
coffee = require('coffee-script');
optparse = require('./../../vendor/optparse-js/src/optparse');
optparse = require('optparse');
BANNER = "coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee path/to/script.coffee";
SWITCHES = [['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-r', '--run', 'compile and run a CoffeeScript'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-e', '--eval', 'compile a string from the command line'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-tr', '--tree', 'print the parse tree that Jison produces'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
WATCH_INTERVAL = 0.5;
@ -27,7 +27,7 @@
};
// The "--help" usage message.
usage = function usage() {
puts('\n' + option_parser.toString() + '\n');
puts('\n' + option_parser.help() + '\n');
return process.exit(0);
};
// The "--version" message.
@ -125,14 +125,13 @@
opts = (options = {});
oparser = (option_parser = new optparse.OptionParser(SWITCHES));
oparser.banner = BANNER;
oparser.add = oparser['on'];
oparser.add('interactive', function() {
return opts.interactive = true;
});
oparser.add('run', function() {
return opts.run = true;
});
oparser.add('output', function(n, dir) {
oparser.add('output', function(dir) {
return opts.output = dir;
});
oparser.add('watch', function() {

116
lib/coffee_script/optparse.js Executable file
View File

@ -0,0 +1,116 @@
(function(){
var LONG_FLAG, OPTIONAL, SHORT_FLAG, build_rule, build_rules, op, spaces;
// Create an OptionParser with a list of valid options.
op = (exports.OptionParser = function OptionParser(rules) {
this.banner = 'Usage: [Options]';
this.options_title = 'Available options:';
this.rules = build_rules(rules);
this.actions = {};
return this;
});
// Add a callback to fire when a particular option is encountered.
op.prototype.add = function add(value, callback) {
return this.actions[value] = callback;
};
// Parse the argument array, calling defined callbacks, returning the remaining non-option arguments.
op.prototype.parse = function parse(args) {
var __a, __b, arg, callback, is_option, results, rule, value;
results = [];
args = args.concat([]);
while (((arg = args.shift()))) {
is_option = false;
__a = this.rules;
for (__b = 0; __b < __a.length; __b++) {
rule = __a[__b];
if (rule.letter === arg || rule.flag === arg) {
callback = this.actions[rule.name];
value = rule.argument && args.shift();
if (callback) {
callback(value);
}
is_option = true;
break;
}
}
if (!(is_option)) {
results.push(arg);
}
}
return results;
};
// Return the help text for this OptionParser, for --help and such.
op.prototype.help = function help() {
var __a, __b, __c, __d, has_shorts, lines, longest, rule, text;
longest = 0;
has_shorts = false;
lines = [this.banner, '', this.options_title];
__a = this.rules;
for (__b = 0; __b < __a.length; __b++) {
rule = __a[__b];
if (rule.letter) {
has_shorts = true;
}
if (rule.flag.length > longest) {
longest = rule.flag.length;
}
}
__c = this.rules;
for (__d = 0; __d < __c.length; __d++) {
rule = __c[__d];
has_shorts ? (text = rule.letter ? spaces(2) + rule.letter + ', ' : spaces(6)) : null;
text += spaces(longest, rule.flag) + spaces(3);
text += rule.description;
lines.push(text);
}
return lines.join('\n');
};
// Private:
// Regex matchers for option flags.
LONG_FLAG = /^(--\w+)/;
SHORT_FLAG = /^(-\w+)/;
OPTIONAL = /\[(.+)\]/;
// Build rules from a list of valid switch tuples in the form:
// [letter-flag, long-flag, help], or [long-flag, help].
build_rules = function build_rules(rules) {
var __a, __b, __c, tuple;
__a = []; __b = rules;
for (__c = 0; __c < __b.length; __c++) {
tuple = __b[__c];
__a.push((function() {
if (tuple.length < 3) {
tuple.unshift(null);
}
return build_rule.apply(this, tuple);
}).call(this));
}
return __a;
};
// Build a rule from a short-letter-flag, long-form-flag, and help text.
build_rule = function build_rule(letter, flag, description) {
var match;
match = flag.match(OPTIONAL);
return {
name: flag.match(LONG_FLAG)[1].substr(2),
letter: letter,
flag: flag,
description: description,
argument: !!(match && match[1])
};
};
// Space-pad a string with the specified number of characters.
spaces = function spaces(num, text) {
var builder;
builder = [];
if (text) {
if (text.length >= num) {
return text;
}
num -= text.length;
builder.push(text);
}
while (num -= 1) {
builder.push(' ');
}
return builder.join('');
};
})();

View File

@ -706,7 +706,7 @@
};
// JavaScript templating a-la ERB, pilfered from John Resig's
// "Secrets of the JavaScript Ninja", page 83.
// Single-quotea fix from Rick Strahl's version.
// Single-quote fix from Rick Strahl's version.
_.template = function template(str, data) {
var c, fn;
c = _.templateSettings;

View File

@ -1,7 +1,7 @@
posix: require 'posix'
path: require 'path'
coffee: require 'coffee-script'
optparse: require('./../../vendor/optparse-js/src/optparse')
optparse: require('optparse')
BANNER: '''
coffee compiles CoffeeScript source files into JavaScript.
@ -41,7 +41,7 @@ exports.run: ->
# The "--help" usage message.
usage: ->
puts '\n' + option_parser.toString() + '\n'
puts '\n' + option_parser.help() + '\n'
process.exit 0
# The "--version" message.
@ -107,11 +107,10 @@ parse_options: ->
opts: options: {}
oparser: option_parser: new optparse.OptionParser SWITCHES
oparser.banner: BANNER
oparser.add: oparser['on']
oparser.add 'interactive', -> opts.interactive: true
oparser.add 'run', -> opts.run: true
oparser.add 'output', (n, dir) -> opts.output: dir
oparser.add 'output', (dir) -> opts.output: dir
oparser.add 'watch', -> opts.watch: true
oparser.add 'print', -> opts.print: true
oparser.add 'lint', -> opts.lint: true

78
src/optparse.coffee Normal file
View File

@ -0,0 +1,78 @@
# Create an OptionParser with a list of valid options.
op: exports.OptionParser: (rules) ->
@banner: 'Usage: [Options]'
@options_title: 'Available options:'
@rules: build_rules(rules)
@actions: {}
this
# Add a callback to fire when a particular option is encountered.
op::add: (value, callback) ->
@actions[value]: callback
# Parse the argument array, calling defined callbacks, returning the remaining non-option arguments.
op::parse: (args) ->
results: []
args: args.concat []
while (arg: args.shift())
is_option: false
for rule in @rules
if rule.letter is arg or rule.flag is arg
callback: @actions[rule.name]
value: rule.argument and args.shift()
callback(value) if callback
is_option: true
break
results.push arg unless is_option
results
# Return the help text for this OptionParser, for --help and such.
op::help: ->
longest: 0
has_shorts: false
lines: [@banner, '', @options_title]
for rule in @rules
has_shorts: true if rule.letter
longest: rule.flag.length if rule.flag.length > longest
for rule in @rules
if has_shorts
text: if rule.letter then spaces(2) + rule.letter + ', ' else spaces(6)
text += spaces(longest, rule.flag) + spaces(3)
text += rule.description
lines.push text
lines.join('\n')
# Private:
# Regex matchers for option flags.
LONG_FLAG: /^(--\w+)/
SHORT_FLAG: /^(-\w+)/
OPTIONAL: /\[(.+)\]/
# Build rules from a list of valid switch tuples in the form:
# [letter-flag, long-flag, help], or [long-flag, help].
build_rules: (rules) ->
for tuple in rules
tuple.unshift(null) if tuple.length < 3
build_rule(tuple...)
# Build a rule from a short-letter-flag, long-form-flag, and help text.
build_rule: (letter, flag, description) ->
match: flag.match(OPTIONAL)
{
name: flag.match(LONG_FLAG)[1].substr(2)
letter: letter
flag: flag
description: description
argument: !!(match and match[1])
}
# Space-pad a string with the specified number of characters.
spaces: (num, text) ->
builder: []
if text
return text if text.length >= num
num -= text.length
builder.push text
while num -= 1 then builder.push ' '
builder.join ''

View File

@ -533,7 +533,7 @@
# JavaScript templating a-la ERB, pilfered from John Resig's
# "Secrets of the JavaScript Ninja", page 83.
# Single-quotea fix from Rick Strahl's version.
# Single-quote fix from Rick Strahl's version.
_.template: (str, data) ->
c: _.templateSettings
fn: new Function 'obj',

View File

@ -1,161 +0,0 @@
optparse-js
===========
Optparse-js is a command line option parser for Javascript. It's slightly based on Ruby's implementation optparse but with some differences (different languages has different needs) such as custom parsers.
All examples in this readme is using [Node.js](http://nodejs.org/). How ever, the library works with all kinds of Javascript implementations.
QUICK START
-----------
The library defines one class, the OptionParser class. The class constructor takes one single argument, a list with a set of rules. Here is a quick example:
// Import the sys library
var sys = require('sys');
// Import the optparse library.
var optparse = require('optparse');
// Define an option called ´´help´´. We give it a quick alias named ´´-h´´
// and a quick help text.
var switches = [
['-h', '--help', 'Shows help sections']
];
// Create a new OptionParser.
var parser = new optparse.OptionParser(switches);
// Hook the help option. The callback will be executed when the OptionParser
// hits the switch ´´-h´´ or ´´--help´´. Each representatio
parser.on('help', function() {
sys.puts('Help');
});
DEFINING RULES
--------------
The OptionParser constructor takes an Array with rules. Each rule is represented by an array (tuple) of two or three values. A typical rule definition may look like this:
['-h', '--help', 'Print this help']
The first value is optional, and represents an alias for the long-named switch (the second value, in this case ´´--help´´).
The second argument is the actual rule. The rule must start with a double dash followed by a switch name (in this case ´help´). The OptionParser also supports special option arguments. Define an option argument in the rule by adding a named argument after the leading double dash and switch name (E.G '--port-number PORT_NUMBER'). The argument is then parsed to the option handler. To define an optional option argument, just add a braces around argument in the rule (E.G '--port-number [PORT_NUMBER]). The OptionParser also supports filter. More on that in in the section called ´Option Filters´.
The third argument is an optional rule description.
OPTION FILTERS
--------------
Filters is a neat feature that let you filter option arguments. The OptionParser itself as already a set of built-in common filter's. These are:
- NUMBER, supports both decimal and hexadecimal numbers.
- DATE, filters arguments that matches YYYY-MM-DD.
- EMAIL, filters arguments that matches my@email.com.
It's simple to use any of the filter above in your rule-set. Here is a quick example how to filter number:
var rules = [
['--first-option NUMBER', 'Takes a number as argument'],
['--second-option [NUMBER]', 'Takes an optional number as argument']
]
You can add your own set of filter by calling the *parser_instance.filter* method:
parser.filter('single_char', function(value) {
if(value.length != 1) throw "Filter mismatch.";
return value;
});
OPTION PARSER
-------------
The OptionParser class has the following properties and methods:
### string banner
An optional usage banner. This text is included when calling ´´toString´´. Default value is: "Usage: [Options]".
### string options_title
An optional title for the options list. This text is included when calling ´´toString´´. Default value is: "Available options:".
### function on(switch_or_arg_index, callback)
Add's a callback for a switch or an argument (defined by index). Switch hooks MUST be typed witout the leading ´´--´´. This example show how to hook a switch:
parser.on('help', function(optional_argument) {
// Show help section
});
And this example show how to hook an argument (an option without the leading - or --):
parser.on(0, function(opt) {
puts('The first non-switch option is:' + opt);
});
It's also possible to define a default handler. The default handler is called when no rule's are meet. Here is an example how to add a ´default handler´:
parser.on(function(opt) {
puts('No handler was defined for option:' + opt);
});
Use the wildcard handler to build a custom ´´on´´ handler.
parser.on('*', function(opt, value) {
puts('option=' + opt + ', value=' + value);
});
### function filter(name, callback)
Adds a new filter extension to the OptionParser instance. The first argument is the name of the filter (trigger). The second argument is the actual filter See the ´OPTION FILTERS´ section for more info.
It's possible to override the default filters by passing the value "_DEFAULT" to the ´´name´´ argument. The name of the filter is automatically transformed into
upper case.
### function halt([callback])
Interrupt's further parsing. This function should be called from an ´on´ -callbacks, to cancel the parsing. This can be useful when the program should ignore all other arguments (when displaying help or version information).
The function also takes an optional callback argument. If the callback argument is specified, a ´halt´ callback will be added (instead of executing the ´halt´ command).
Here is an example how to add an ´on_halt´ callback:
parser.halt(function() {
puts('An option callback interupted the parser');
});
### function parse(arguments)
Start's parsing of arguments. This should be the last thing you do.
### function options()
Returns an Array with all defined option rules
### function toString()
Returns a string representation of this OptionParser instance (a formatted help section).
MORE EXAMPLES
-------------
See examples/nodejs-test.js and examples/browser-test-html for more info how to
use the script.
SUGGESTIONS
-----------
All comments in how to improve this library is very welcome. Feel free post suggestions to the [Issue tracker](http://github.com/jfd/optparse-js/issues), or even better, fork the repository to implement your own features.
LICENSE
-------
Released under a MIT-style license.
COPYRIGHT
---------
Copyright (c) 2009 Johan Dahlberg

View File

@ -1 +0,0 @@
- Support for Argument lists (for switches)

View File

@ -1,75 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>optparse.js example</title>
<script type="text/javascript" charset="utf-8" src="../src/optparse.js"></script>
<script>
// Arguments to be passed to the parser
var ARGS = ['-p', 'This is a message', '-i', 'test.html', '--debug'];
// Define some options
var SWITCHES = [
['-i', '--include-file FILE', "Includes a file"],
['-p', '--print [MESSAGE]', "Prints a message on screen"],
['-d', '--debug', "Enables debug mode"],
];
function puts(msg) {
var body = document.getElementById('body');
var pre = document.createElement('pre');
pre.innerHTML = msg;
body.appendChild(pre);
}
function onLoad() {
puts("optparse.js");
// Create a new OptionParser with defined switches
var parser = new optparse.OptionParser(SWITCHES);
// Internal variable to store options.
var options = {
debug: false,
files: []
};
// Handle the first argument (switches excluded)
parser.on(0, function(value) {
puts("First non-switch argument is: " + value);
});
// Handle the --include-file switch
parser.on('include-file', function(value) {
options.files.push(value);
});
// Handle the --print switch
parser.on('print', function(value) {
puts('PRINT: ' + value);
});
// Handle the --debug switch
parser.on('debug', function() {
options.debug = true;
});
// Parse command line arguments
parser.parse(ARGS);
// Output all files that was included.
puts("No of files to include: " + options.files.length);
for(var i = 0; i < options.files.length; i++) {
puts("File [" + (i + 1) + "]:" + options.files[i]);
}
// Is debug-mode enabled?
puts("Debug mode is set to: " + options.debug);
}
</script>
</head>
<body id="body" onload="onLoad()">
</body>
</html>

View File

@ -1,88 +0,0 @@
// Import the optparse script
var optparse = require('../src/optparse');
process.mixin(require("utils"));
// Define some options
var SWITCHES = [
['-i', '--include-file FILE', "Includes a file"],
['-p', '--print [MESSAGE]', "Prints an optional message on screen"],
['-d', '--debug', "Enables debug mode"],
['-H', '--help', "Shows this help section"],
['--date DATE', "A date. A date is expected E.G. 2009-01-14"],
['--number NUMBER', "A Number. Supported formats are 123, 123.123, 0xA123"],
['--other NAME', "No handler defined for this option. Will be handled by the wildcard handler."],
];
// Create a new OptionParser with defined switches
var parser = new optparse.OptionParser(SWITCHES), print_summary = true,
first_arg;
parser.banner = 'Usage: nodejs-test.js [options]';
// Internal variable to store options.
var options = {
debug: false,
files: [],
number: undefined,
date: undefined
};
// Handle the first argument (switches excluded)
parser.on(0, function(value) {
first_arg = value;
});
// Handle the --include-file switch
parser.on('include-file', function(value) {
options.files.push(value);
});
// Handle the --print switch
parser.on('print', function(value) {
puts('PRINT: ' + (value || 'No message entered'));
});
// Handle the --date switch
parser.on('date', function(value) {
options.date = value;
});
// Handle the --number switch
parser.on('number', function(value) {
options.number = value;
});
// Handle the --debug switch
parser.on('debug', function() {
options.debug = true;
});
// Handle the --help switch
parser.on('help', function() {
puts(parser.toString());
print_summary = false;
});
// Set a default handler
parser.on('*', function(opt, value) {
puts('wild handler for ' + opt + ', value=' + value);
});
// Parse command line arguments
parser.parse(process.ARGV);
if(print_summary) {
puts("First non-switch argument is: " + first_arg);
// Output all files that was included.
puts("No of files to include: " + options.files.length);
for(var i = 0; i < options.files.length; i++) {
puts("File [" + (i + 1) + "]:" + options.files[i]);
}
// Is debug-mode enabled?
puts("Debug mode is set to: " + options.debug);
puts("Number value is: " + options.number);
puts("Date value is: " + options.date);
}

View File

@ -1,309 +0,0 @@
// Optparse.js 1.0 - Option Parser for Javascript
//
// Copyright (c) 2009 Johan Dahlberg
//
// See README.md for license.
//
var optparse = {};
try{ optparse = exports } catch(e) {}; // Try to export the lib for node.js
(function(self) {
var VERSION = '1.0';
var LONG_SWITCH_RE = /^--\w/;
var SHORT_SWITCH_RE = /^-\w/;
var NUMBER_RE = /^(0x[A-Fa-f0-9]+)|([0-9]+\.[0-9]+)|(\d+)$/;
var DATE_RE = /^\d{4}-(0[0-9]|1[0,1,2])-([0,1,2][0-9]|3[0,1])$/;
var EMAIL_RE = /^([0-9a-zA-Z]+([_.-]?[0-9a-zA-Z]+)*@[0-9a-zA-Z]+[0-9,a-z,A-Z,.,-]*(.){1}[a-zA-Z]{2,4})+$/;
var EXT_RULE_RE = /(\-\-[\w_-]+)\s+([\w\[\]_-]+)|(\-\-[\w_-]+)/;
var ARG_OPTIONAL_RE = /\[(.+)\]/;
// The default switch argument filter to use, when argument name doesnt match
// any other names.
var DEFAULT_FILTER = '_DEFAULT';
var PREDEFINED_FILTERS = {};
// The default switch argument filter. Parses the argument as text.
function filter_text(value) {
return value;
}
// Switch argument filter that expects an integer, HEX or a decimal value. An
// exception is throwed if the criteria is not matched.
// Valid input formats are: 0xFFFFFFF, 12345 and 1234.1234
function filter_number(value) {
var m = NUMBER_RE(value);
if(m == null) throw OptError('Expected a number representative');
if(m[1]) {
// The number is in HEX format. Convert into a number, then return it
return parseInt(m[1], 16);
} else {
// The number is in regular- or decimal form. Just run in through
// the float caster.
return parseFloat(m[2] || m[3]);
}
};
// Switch argument filter that expects a Date expression. The date string MUST be
// formated as: "yyyy-mm-dd" An exception is throwed if the criteria is not
// matched. An DATE object is returned on success.
function filter_date(value) {
var m = DATE_RE(value);
if(m == null) throw OptError('Expected a date representation in the "yyyy-mm-dd" format.');
return new Date(parseInt(m[0]), parseInt(m[1]), parseInt(m[2]));
};
// Switch argument filter that expects an email address. An exception is throwed
// if the criteria doesn`t match.
function filter_email(value) {
var m = EMAIL_RE(value);
if(m == null) throw OptError('Excpeted an email address.');
return m[1];
}
// Register all predefined filters. This dict is used by each OptionParser
// instance, when parsing arguments. Custom filters can be added to the parser
// instance by calling the "add_filter" -method.
PREDEFINED_FILTERS[DEFAULT_FILTER] = filter_text;
PREDEFINED_FILTERS['TEXT'] = filter_text;
PREDEFINED_FILTERS['NUMBER'] = filter_number;
PREDEFINED_FILTERS['DATE'] = filter_date;
PREDEFINED_FILTERS['EMAIL'] = filter_email;
// Buildes rules from a switches collection. The switches collection is defined
// when constructing a new OptionParser object.
function build_rules(filters, arr) {
var rules = [];
for(var i=0; i<arr.length; i++) {
var r = arr[i], rule
if(!contains_expr(r)) throw OptError('Rule MUST contain an option.');
switch(r.length) {
case 1:
rule = build_rule(filters, r[0]);
break;
case 2:
var expr = LONG_SWITCH_RE(r[0]) ? 0 : 1;
var alias = expr == 0 ? -1 : 0;
var desc = alias == -1 ? 1 : -1;
rule = build_rule(filters, r[alias], r[expr], r[desc]);
break;
case 3:
rule = build_rule(filters, r[0], r[1], r[2]);
break;
default:
case 0:
continue;
}
rules.push(rule)
}
return rules;
}
// Builds a rule with specified expression, short style switch and help. This
// function expects a dict with filters to work correctly.
//
// Return format:
// name The name of the switch.
// short The short style switch
// long The long style switch
// decl The declaration expression (the input expression)
// desc The optional help section for the switch
// optional_arg Indicates that switch argument is optional
// filter The filter to use when parsing the arg. An
// <<undefined>> value means that the switch does
// not take anargument.
function build_rule(filters, short, expr, desc) {
var optional, filter;
var m = expr.match(EXT_RULE_RE);
if(m == null) throw OptError('The switch is not well-formed.');
var long = m[1] || m[3];
if(m[2] != undefined) {
// A switch argument is expected. Check if the argument is optional,
// then find a filter that suites.
var optional_match = ARG_OPTIONAL_RE(m[2]);
var filter_name = optional_match === null ? m[2] : optional_match[1];
optional = optional_match !== null;
filter = filters[filter_name];
if(filter === undefined) filter = filters[DEFAULT_FILTER];
}
return {
name: long.substr(2),
short: short,
long: long,
decl: expr,
desc: desc,
optional_arg: optional,
filter: filter
}
}
// Loop's trough all elements of an array and check if there is valid
// options expression within. An valid option is a token that starts
// double dashes. E.G. --my_option
function contains_expr(arr) {
if(!arr || !arr.length) return false;
var l = arr.length;
while(l-- > 0) if(LONG_SWITCH_RE(arr[l])) return true;
return false;
}
// Extends destination object with members of source object
function extend(dest, src) {
var result = dest;
for(var n in src) {
result[n] = src[n];
}
return result;
}
// Appends spaces to match specified number of chars
function spaces(arg1, arg2) {
var l, builder = [];
if(arg1.constructor === Number) {
l = arg1;
} else {
if(arg1.length == arg2) return arg1;
l = arg2 - arg1.length;
builder.push(arg1);
}
while(l-- > 0) builder.push(' ');
return builder.join('');
}
// Create a new Parser object that can be used to parse command line arguments.
//
//
function Parser(rules) {
return new OptionParser(rules);
}
// Creates an error object with specified error message.
function OptError(msg) {
return new function() {
this.msg = msg;
this.toString = function() {
return this.msg;
}
}
}
function OptionParser(rules) {
this.banner = 'Usage: [Options]';
this.options_title = 'Available options:'
this._rules = rules;
this._halt = false;
this.filters = extend({}, PREDEFINED_FILTERS);
this.on_args = {};
this.on_switches = {};
this.on_halt = function() {};
this.default_handler = function() {};
}
OptionParser.prototype = {
// Adds args and switchs handler.
on: function(value, fn) {
if(value.constructor === Function ) {
this.default_handler = value;
} else if(value.constructor === Number) {
this.on_args[value] = fn;
} else {
this.on_switches[value] = fn;
}
},
// Adds a custom filter to the parser. It's possible to override the
// default filter by passing the value "_DEFAULT" to the ´´name´´
// argument. The name of the filter is automatically transformed into
// upper case.
filter: function(name, fn) {
this.filters[name.toUpperCase()] = fn;
},
// Parses specified args. Returns remaining arguments.
parse: function(args) {
var result = [], callback;
var rules = build_rules(this.filters, this._rules);
var tokens = args.concat([]);
while((token = tokens.shift()) && this._halt == false) {
if(LONG_SWITCH_RE(token) || SHORT_SWITCH_RE(token)) {
var arg = undefined;
// The token is a long or a short switch. Get the corresponding
// rule, filter and handle it. Pass the switch to the default
// handler if no rule matched.
for(var i = 0; i < rules.length; i++) {
var rule = rules[i];
if(rule.long == token || rule.short == token) {
if(rule.filter !== undefined) {
arg = tokens.shift();
if(!LONG_SWITCH_RE(arg) && !SHORT_SWITCH_RE(arg)) {
try {
arg = rule.filter(arg);
} catch(e) {
throw OptError(token + ': ' + e.toString());
}
} else if(rule.optional_arg) {
tokens.unshift(arg);
} else {
throw OptError('Expected switch argument.');
}
}
callback = this.on_switches[rule.name];
if (!callback) callback = this.on_switches['*'];
if(callback) callback.apply(this, [rule.name, arg]);
break;
}
}
if(i == rules.length) this.default_handler.apply(this, [token]);
} else {
// Did not match long or short switch. Parse the token as a
// normal argument.
callback = this.on_args[result.length];
result.push(token);
if(callback) callback.apply(this, [token]);
}
}
return this._halt ? this.on_halt.apply(this, []) : result;
},
// Returns an Array with all defined option rules
options: function() {
return build_rules(this.filters, this._rules);
},
// Add an on_halt callback if argument ´´fn´´ is specified. on_switch handlers can
// call instance.halt to abort the argument parsing. This can be useful when
// displaying help or version information.
halt: function(fn) {
this._halt = fn === undefined
if(fn) this.on_halt = fn;
},
// Returns a string representation of this OptionParser instance.
toString: function() {
var builder = [this.banner, '', this.options_title],
shorts = false, longest = 0, rule;
var rules = build_rules(this.filters, this._rules);
for(var i = 0; i < rules.length; i++) {
rule = rules[i];
// Quick-analyze the options.
if(rule.short) shorts = true;
if(rule.decl.length > longest) longest = rule.decl.length;
}
for(var i = 0; i < rules.length; i++) {
var text;
rule = rules[i];
if(shorts) {
if(rule.short) text = spaces(2) + rule.short + ', ';
else text = spaces(6);
}
text += spaces(rule.decl, longest) + spaces(3);
text += rule.desc;
builder.push(text);
}
return builder.join('\n');
}
}
self.VERSION = VERSION;
self.OptionParser = OptionParser;
})(optparse);