unscripted 0.4.3 unscripted: ^0.4.3 copied to clipboard
Declarative command-line interface programming.
unscripted #
Define command-line interfaces using ordinary dart methods and classes.
##Installation
Add the unscripted package to your pubspec.yaml dependencies:
unscripted: '>=0.4.0 <0.5.0'
##Usage
The following greet.dart script outputs a configurable greeting:
#!/usr/bin/env dart
import 'package:unscripted/unscripted.dart';
main(arguments) => declare(greet).execute(arguments);
// All metadata annotations are optional.
@Command(help: 'Print a configurable greeting', plugins: const [const Completion()])
@ArgExample('--salutation Hi --enthusiasm 3 Bob', help: 'enthusiastic')
greet(
@Rest(help: 'Name(s) to greet.')
List<String> who, {
@Option(help: 'Alternate word to greet with e.g. "Hi".')
String salutation : 'Hello',
@Option(help: 'How many !\'s to append.')
int enthusiasm : 0,
@Flag(abbr: 'l', help: 'Put names on separate lines.')
bool lineMode : false
}) {
print(salutation +
who.map((w) => (lineMode ? '\n ' : ' ') + w).join(',') +
'!' * enthusiasm);
}
We can call this script as follows:
$ greet.dart Bob
Hello Bob
$ greet.dart --salutation Hi --enthusiasm 3 -l Alice Bob
Hi
Alice,
Bob!!!
##Automatic --help
A --help
/-h
flag is automatically defined:
$ greet.dart --help
Description:
Print a configurable greeting
Usage:
greet.dart [options] [WHO]...
Options:
--salutation=<greeting> Alternate <greeting> to greet with e.g. "Hi".
--enthusiasm How many !'s to append.
-l, --line-mode Put names on separate lines.
--completion Tab completion for this command.
[install] Install completion script to .bashrc/.zshrc.
[print] Print completion script to stdout.
[uninstall] Uninstall completion script from .bashrc/.zshrc.
-h, --help Print this usage information.
Examples:
greet.dart --salutation Hi --enthusiasm 3 Bob # enthusiastic
##Sub-Commands
Sub-commands are represented as SubCommand
-annotated instance methods of
classes, as seen in the following server.dart:
#!/usr/bin/env dart
import 'dart:io';
import 'package:unscripted/unscripted.dart';
import 'package:path/path.dart' as path;
main(arguments) => declare(Server).execute(arguments);
class Server {
final String configPath;
@Command(
help: 'Manages a server',
plugins: const [const Completion()])
Server({this.configPath: 'config.xml'});
@SubCommand(help: 'Start the server')
start({bool clean}) {
print('''
Starting the server.
Config path: $configPath''');
}
@SubCommand(help: 'Stop the server')
stop() {
print('Stopping the server.');
}
}
We can call this script as follows:
$ server.dart start --config-path my-config.xml --clean
Starting the server.
Config path: my-config.xml
Help is also available for sub-commands:
$ server.dart help
Available commands:
start
help
stop
Use "server.dart help [command]" for more information about a command.
$ server.dart help stop
Description:
Stop the server
Usage:
server.dart stop [options]
Options:
-h, --help Print this usage information.
##Parsers
Any value-taking argument (option, positional, rest) can have a "parser"
responsible for validating and transforming the string passed on the command
line. You can give an argument a parser simply by giving it a type (such as
int
or DateTime
) which has a static parse
method, or by specifying the
parser
named argument of the argument's metadata (Option
, Positional
, or
Rest
).
##Plugins
Plugins allow you to mixin reusable chunks of cli-specific functionality (options/flags/commands) on top of your base interface.
To add a plugin to your script, just add an instance of the associated plugin
class to the plugins
named argument of your @Command
annotation. The
following plugins are available:
###Tab Completion
Add bash/zsh tab completion to your script:
#!/usr/bin/env dart
// ...
@Command(plugins: const [const Completion()])
(Once pub supports cli's, the "shebang" line will no longer be required.)
If your script already has sub-commands, this will add a completion
sub-command (similar to npm completion), otherwise it adds a
--completion
option. These can then be used as follows:
# Try the tab-completion without permanently installing.
. <(greet.dart --completion print)
. <(server.dart completion print)
# Install the completion script to .bashrc/.zshrc depending on current shell.
# No-op if already installed.
greet.dart --completion install
server.dart completion install
# Uninstall a previously installed completion script.
# No-op if not installed.
greet.dart --completion uninstall
server.dart completion uninstall
Once installed, the user will be able to tab-complete all aspects of your cli, for example:
Option/Flag names: Say your script is a dart method with a
longOptionName
named parameter. This becomes --long-option-name
in your
cli, and once completion is installed, the user can type --l[TAB]
and it will
be completed to --long-option-name
. It will also expand short options to their
long equivalents, e.g. -vh[TAB]
becomes --verbose --help
.
Commands: If your script is a dart class having a @SubCommand() longCommandName
method, that becomes a long-command-name
sub-command in your
cli, and the user can type l[TAB]
and it will be completed to
long-command-name
.
Option/Positional/Rest values: The allowed
named parameter of Option
,
Positional
, and Rest
specifies the allowed values, and thus completions,
for those parameters. For example if you have
@Option(allowed: const ['red', 'yellow', 'green']) textColor
, and the user
types --text-color g[TAB]
this will become --text-color green
. allowed
can also be a callback of one of the following forms:
Iterable<String> complete(String text);
Iterable<String> complete();
Future<Iterable<String>> complete(String text);
Future<Iterable<String>> complete();
where if an arg (e.g. text
here) is specified, it represents the last partial
word typed by the user when completion is requested, which can be used to filter
the results to match that prefix. If the arg is omitted, the filtering is done
automatically for you. For example if the option/positional/rest represents a
file name, you could emulate the builtin shell file name completion by returning
a list of filenames in the current directory.
Tab completion is supported in cygwin, with one minor bug (#64).
###Other Plugins
There are several other plugins planned, and also the ability to write your own is planned, see #62.
##Demo
cat.dart is a complete implementation of the *nix cat
utility using unscripted.