mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
483 lines
19 KiB
HTML
483 lines
19 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<html>
|
||
<head>
|
||
<title>optparse.coffee</title>
|
||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
|
||
<link rel="stylesheet" media="all" href="docco.css" />
|
||
</head>
|
||
<body>
|
||
<div id="container">
|
||
<div id="background"></div>
|
||
|
||
<ul id="jump_to">
|
||
<li>
|
||
<a class="large" href="javascript:void(0);">Jump To …</a>
|
||
<a class="small" href="javascript:void(0);">+</a>
|
||
<div id="jump_wrapper">
|
||
<div id="jump_page_wrapper">
|
||
<div id="jump_page">
|
||
|
||
|
||
<a class="source" href="browser.html">
|
||
browser.coffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="cake.html">
|
||
cake.coffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="coffeescript.html">
|
||
coffeescript.coffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="command.html">
|
||
command.coffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="grammar.html">
|
||
grammar.coffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="helpers.html">
|
||
helpers.coffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="index.html">
|
||
index.coffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="lexer.html">
|
||
lexer.coffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="nodes.html">
|
||
nodes.coffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="optparse.html">
|
||
optparse.coffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="register.html">
|
||
register.coffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="repl.html">
|
||
repl.coffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="rewriter.html">
|
||
rewriter.coffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="scope.html">
|
||
scope.litcoffee
|
||
</a>
|
||
|
||
|
||
<a class="source" href="sourcemap.html">
|
||
sourcemap.litcoffee
|
||
</a>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
|
||
<ul class="sections">
|
||
|
||
<li id="title">
|
||
<div class="annotation">
|
||
<h1>optparse.coffee</h1>
|
||
</div>
|
||
</li>
|
||
|
||
|
||
|
||
<li id="section-1">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-1">¶</a>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>{repeat} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./helpers'</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-2">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-2">¶</a>
|
||
</div>
|
||
<p>A simple <strong>OptionParser</strong> class to parse option flags from the command-line.
|
||
Use it like so:</p>
|
||
<pre><code>parser = <span class="hljs-keyword">new</span> OptionParser switches, helpBanner
|
||
options = parser.parse process.argv
|
||
</code></pre><p>The first non-option is considered to be the start of the file (and file
|
||
option) list, and all subsequent arguments are left unparsed.</p>
|
||
<p>The <code>coffee</code> command uses an instance of <strong>OptionParser</strong> to parse its
|
||
command-line arguments in <code>src/command.coffee</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>exports.OptionParser = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OptionParser</span></span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-3">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-3">¶</a>
|
||
</div>
|
||
<p>Initialize with a list of valid options, in the form:</p>
|
||
<pre><code>[short-flag, long-flag, description]
|
||
</code></pre><p>Along with an optional banner for the usage help.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> constructor: <span class="hljs-function"><span class="hljs-params">(ruleDeclarations, @banner)</span> -></span>
|
||
@rules = buildRules ruleDeclarations</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-4">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-4">¶</a>
|
||
</div>
|
||
<p>Parse the list of arguments, populating an <code>options</code> object with all of the
|
||
specified options, and return it. Options after the first non-option
|
||
argument are treated as arguments. <code>options.arguments</code> will be an array
|
||
containing the remaining arguments. This is a simpler API than many option
|
||
parsers that allow you to attach callback actions for every flag. Instead,
|
||
you’re responsible for interpreting the options object.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> parse: <span class="hljs-function"><span class="hljs-params">(args)</span> -></span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-5">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-5">¶</a>
|
||
</div>
|
||
<p>The CoffeeScript option parser is a little odd; options after the first
|
||
non-option argument are treated as non-option arguments themselves.
|
||
Optional arguments are normalized by expanding merged flags into multiple
|
||
flags. This allows you to have <code>-wl</code> be the same as <code>--watch --lint</code>.
|
||
Note that executable scripts with a shebang (<code>#!</code>) line should use the
|
||
line <code>#!/usr/bin/env coffee</code>, or <code>#!/absolute/path/to/coffee</code>, without a
|
||
<code>--</code> argument after, because that will fail on Linux (see #3946).</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> {rules, positional} = normalizeArguments args, @rules.flagDict
|
||
options = {}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-6">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-6">¶</a>
|
||
</div>
|
||
<p>The <code>argument</code> field is added to the rule instance non-destructively by
|
||
<code>normalizeArguments</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> {hasArgument, argument, isList, name} <span class="hljs-keyword">in</span> rules
|
||
<span class="hljs-keyword">if</span> hasArgument
|
||
<span class="hljs-keyword">if</span> isList
|
||
options[name] ?= []
|
||
options[name].push argument
|
||
<span class="hljs-keyword">else</span>
|
||
options[name] = argument
|
||
<span class="hljs-keyword">else</span>
|
||
options[name] = <span class="hljs-literal">true</span>
|
||
|
||
<span class="hljs-keyword">if</span> positional[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'--'</span>
|
||
options.doubleDashed = <span class="hljs-literal">yes</span>
|
||
positional = positional[<span class="hljs-number">1.</span>.]
|
||
|
||
options.arguments = positional
|
||
options</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-7">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-7">¶</a>
|
||
</div>
|
||
<p>Return the help text for this <strong>OptionParser</strong>, listing and describing all
|
||
of the valid options, for <code>--help</code> and such.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> help: <span class="hljs-function">-></span>
|
||
lines = []
|
||
lines.unshift <span class="hljs-string">"<span class="hljs-subst">#{@banner}</span>\n"</span> <span class="hljs-keyword">if</span> @banner
|
||
<span class="hljs-keyword">for</span> rule <span class="hljs-keyword">in</span> @rules.ruleList
|
||
spaces = <span class="hljs-number">15</span> - rule.longFlag.length
|
||
spaces = <span class="hljs-keyword">if</span> spaces > <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> repeat <span class="hljs-string">' '</span>, spaces <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>
|
||
letPart = <span class="hljs-keyword">if</span> rule.shortFlag <span class="hljs-keyword">then</span> rule.shortFlag + <span class="hljs-string">', '</span> <span class="hljs-keyword">else</span> <span class="hljs-string">' '</span>
|
||
lines.push <span class="hljs-string">' '</span> + letPart + rule.longFlag + spaces + rule.description
|
||
<span class="hljs-string">"\n<span class="hljs-subst">#{ lines.join(<span class="hljs-string">'\n'</span>) }</span>\n"</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-8">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-8">¶</a>
|
||
</div>
|
||
<h2 id="helpers">Helpers</h2>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-9">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-9">¶</a>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-10">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-10">¶</a>
|
||
</div>
|
||
<p>Regex matchers for option flags on the command line and their rules.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>LONG_FLAG = <span class="hljs-regexp">/^(--\w[\w\-]*)/</span>
|
||
SHORT_FLAG = <span class="hljs-regexp">/^(-\w)$/</span>
|
||
MULTI_FLAG = <span class="hljs-regexp">/^-(\w{2,})/</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-11">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-11">¶</a>
|
||
</div>
|
||
<p>Matches the long flag part of a rule for an option with an argument. Not
|
||
applied to anything in process.argv.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>OPTIONAL = <span class="hljs-regexp">/\[(\w+(\*?))\]/</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-12">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-12">¶</a>
|
||
</div>
|
||
<p>Build and return the list of option rules. If the optional <em>short-flag</em> is
|
||
unspecified, leave it out by padding with <code>null</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">buildRules</span> = <span class="hljs-params">(ruleDeclarations)</span> -></span>
|
||
ruleList = <span class="hljs-keyword">for</span> tuple <span class="hljs-keyword">in</span> ruleDeclarations
|
||
tuple.unshift <span class="hljs-literal">null</span> <span class="hljs-keyword">if</span> tuple.length < <span class="hljs-number">3</span>
|
||
buildRule tuple...
|
||
flagDict = {}
|
||
<span class="hljs-keyword">for</span> rule <span class="hljs-keyword">in</span> ruleList</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-13">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-13">¶</a>
|
||
</div>
|
||
<p><code>shortFlag</code> is null if not provided in the rule.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> flag <span class="hljs-keyword">in</span> [rule.shortFlag, rule.longFlag] <span class="hljs-keyword">when</span> flag?
|
||
<span class="hljs-keyword">if</span> flagDict[flag]?
|
||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error <span class="hljs-string">"flag <span class="hljs-subst">#{flag}</span> for switch <span class="hljs-subst">#{rule.name}</span>
|
||
was already declared for switch <span class="hljs-subst">#{flagDict[flag].name}</span>"</span>
|
||
flagDict[flag] = rule
|
||
|
||
{ruleList, flagDict}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-14">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-14">¶</a>
|
||
</div>
|
||
<p>Build a rule from a <code>-o</code> short flag, a <code>--output [DIR]</code> long flag, and the
|
||
description of what the option does.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">buildRule</span> = <span class="hljs-params">(shortFlag, longFlag, description)</span> -></span>
|
||
match = longFlag.match(OPTIONAL)
|
||
shortFlag = shortFlag?.match(SHORT_FLAG)[<span class="hljs-number">1</span>]
|
||
longFlag = longFlag.match(LONG_FLAG)[<span class="hljs-number">1</span>]
|
||
{
|
||
name: longFlag.replace <span class="hljs-regexp">/^--/</span>, <span class="hljs-string">''</span>
|
||
shortFlag: shortFlag
|
||
longFlag: longFlag
|
||
description: description
|
||
hasArgument: !!(match <span class="hljs-keyword">and</span> match[<span class="hljs-number">1</span>])
|
||
isList: !!(match <span class="hljs-keyword">and</span> match[<span class="hljs-number">2</span>])
|
||
}
|
||
<span class="hljs-function">
|
||
<span class="hljs-title">normalizeArguments</span> = <span class="hljs-params">(args, flagDict)</span> -></span>
|
||
rules = []
|
||
positional = []
|
||
needsArgOpt = <span class="hljs-literal">null</span>
|
||
<span class="hljs-keyword">for</span> arg, argIndex <span class="hljs-keyword">in</span> args</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-15">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-15">¶</a>
|
||
</div>
|
||
<p>If the previous argument given to the script was an option that uses the
|
||
next command-line argument as its argument, create copy of the option’s
|
||
rule with an <code>argument</code> field.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> needsArgOpt?
|
||
withArg = Object.assign {}, needsArgOpt.rule, {argument: arg}
|
||
rules.push withArg
|
||
needsArgOpt = <span class="hljs-literal">null</span>
|
||
<span class="hljs-keyword">continue</span>
|
||
|
||
multiFlags = arg.match(MULTI_FLAG)?[<span class="hljs-number">1</span>]
|
||
.split(<span class="hljs-string">''</span>)
|
||
.map (flagName) -> <span class="hljs-string">"-<span class="hljs-subst">#{flagName}</span>"</span>
|
||
<span class="hljs-keyword">if</span> multiFlags?
|
||
multiOpts = multiFlags.map (flag) ->
|
||
rule = flagDict[flag]
|
||
<span class="hljs-keyword">unless</span> rule?
|
||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error <span class="hljs-string">"unrecognized option <span class="hljs-subst">#{flag}</span> in multi-flag <span class="hljs-subst">#{arg}</span>"</span>
|
||
{rule, flag}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-16">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-16">¶</a>
|
||
</div>
|
||
<p>Only the last flag in a multi-flag may have an argument.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> [innerOpts..., lastOpt] = multiOpts
|
||
<span class="hljs-keyword">for</span> {rule, flag} <span class="hljs-keyword">in</span> innerOpts
|
||
<span class="hljs-keyword">if</span> rule.hasArgument
|
||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error <span class="hljs-string">"cannot use option <span class="hljs-subst">#{flag}</span> in multi-flag <span class="hljs-subst">#{arg}</span> except
|
||
as the last option, because it needs an argument"</span>
|
||
rules.push rule
|
||
<span class="hljs-keyword">if</span> lastOpt.rule.hasArgument
|
||
needsArgOpt = lastOpt
|
||
<span class="hljs-keyword">else</span>
|
||
rules.push lastOpt.rule
|
||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ([LONG_FLAG, SHORT_FLAG].some (pat) -> arg.match(pat)?)
|
||
singleRule = flagDict[arg]
|
||
<span class="hljs-keyword">unless</span> singleRule?
|
||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error <span class="hljs-string">"unrecognized option <span class="hljs-subst">#{arg}</span>"</span>
|
||
<span class="hljs-keyword">if</span> singleRule.hasArgument
|
||
needsArgOpt = {rule: singleRule, flag: arg}
|
||
<span class="hljs-keyword">else</span>
|
||
rules.push singleRule
|
||
<span class="hljs-keyword">else</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-17">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-17">¶</a>
|
||
</div>
|
||
<p>This is a positional argument.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> positional = args[argIndex..]
|
||
<span class="hljs-keyword">break</span>
|
||
|
||
<span class="hljs-keyword">if</span> needsArgOpt?
|
||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error <span class="hljs-string">"value required for <span class="hljs-subst">#{needsArgOpt.flag}</span>, but it was the last
|
||
argument provided"</span>
|
||
{rules, positional}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</div>
|
||
</body>
|
||
</html>
|