smart_arg 1.1.1

  • Readme
  • Changelog
  • Example
  • Installing
  • 68

Smart Arg #

Build Status codecov Pub

A source generated, simple to use command line argument parser. The main rationale behind this argument parser is the use of a class to store the argument values. Therefore, you gain static type checking and code completion.

Types currently supported are: bool, int, double, String, File, and Directory. Defaults can be supplied as any other Dart class and one can determine if a parameter was set based on it's value being null or not. Types can also be defined as a List<T> to support multiple arguments of the same name to be specified on the command line. Anything passed on the command line that is not an option will be considered an extra, of which you can demand a minimum and/or maximum requirement.

Through the use of annotations, each parameter (and main class) can have various attributes set such as help text, if the parameter is required, if the file must exist on disk, can the parameter be negated, a short alias, and more.

Beautiful help is of course generated automatically when the user gives an incorrect parameter or misses a required parameter or extra.

Simple Example #

import 'dart:io';

import 'package:smart_arg/smart_arg.dart';

import 'readme_example.reflectable.dart';

@SmartArg.reflectable
@Parser(description: 'Hello World application')
class Args extends SmartArg {
  @StringArgument(help: 'Name of person to say hello to')
  String name = 'World';    // Default to World

  @StringArgument(
    help: 'Greeting text to use',
    mustBeOneOf: ['Hello', 'Goodbye'],
  )
  String greeting = 'Hello'; // Default to Hello

  @IntegerArgument(
    help: 'Number of times to greet the person',
    isRequired: true,
    minimum: 1,
    maximum: 100,
  )
  int count;

  @HelpArgument()
  bool help = false;
}

void main(List<String> arguments) {
  initializeReflectable();

  var args = Args()..parse(arguments);
  if (args.help) {
    print(args.usage());
    exit(0);
  }

  for (int i = 0; i < args.count; i++) {
    print('${args.greeting}, ${args.name}!');
  }
}

Please see the API documentation for a better understanding of what Argument types exist as well as their individual options.

Help Output #

The help output of the above example is:

Hello World application

  --name         Name of person to say hello to
  --greeting     Greeting text to use
                 must be one of Hello, Goodbye
  --count        Number of times to greet the person
                 [REQUIRED]
  -h, --help, -? Show help

Build Process #

smart_arg relies on the reflectable package. Therefore, you must add to your build process. Your build.yaml file should look similar to:

targets:
  $default:
    builders:
      reflectable:
        generate_for:
          - bin/main.dart

Also, before you can execute your program and any time you change your SmartArg class, you must execute the builder:

$ pub run build_runner build

Complete Example #

A more complex example smart_arg_example.dart produces the following output:

Example smart arg application

Group 1
  This is some long text that explains this section in detail. Blah blah blah
  blah blah blah blah blah. This will be wrapped as needed. Thus, it will
  display beautifully in the console.

  --names        no help available
  -r, --header   Report header text
  --filename     Filename to report stats on

  This is just a single sentence but even it will be wrapped if necessary

Group 2 -- OTHER
  Help before

  --count        Count of times to say hello
  --silly        Some other silly parameter to show double parsing. This also
                 has a very long description that should word wrap in the
                 output and produce beautiful display.
  -v, --verbose, --no-verbose
                 Turn verbose mode on.

                 This is an example also of using multi-line help text that
                 is formatted inside of the editor. This should be one
                 paragraph. I'll add some more content here. This will be the
                 last sentence of the first paragraph.

                 This is another paragraph formatted very narrowly in the
                 code editor. Does it look the same as the one above? I sure
                 hope that it does. It would make help display very easy to
                 implement.
  -h, --help, -? Show help

  Help after

This is a simple application that does nothing and contains silly arguments.
It simply shows how the smart_arg library can be used.

No one should really try to use this program outside of those interested in
using smart_arg in their own applications.

SECTION 2
  This is more extended text that can be put into its own section.

Command Execution #

More complex command line applications often times have commands. These commands then also have options of their own. SmartArg accomplishes this very easily:

import 'dart:io';

import 'package:smart_arg/smart_arg.dart';

import 'command_example.reflectable.dart';

@SmartArg.reflectable
@Parser(description: 'get file from remote server')
class GetCommand extends SmartArgCommand {
  @BooleanArgument(help: 'Should the file be removed after downloaded?')
  bool removeAfterGet;

  @HelpArgument()
  bool help;

  @override
  void execute(SmartArg parentArguments) {
    if (help == true) {
      print(usage());
      exit(0);
    }

    if ((parentArguments as Args).verbose == true) {
      print('Verbose is on');
    } else {
      print('Verbose is off');
    }

    print('Getting file...');

    if (removeAfterGet == true) {
      print('Removing file on remote server (not really)');
    }
  }
}

@SmartArg.reflectable
@Parser(description: 'put file onto remote server')
class PutCommand extends SmartArgCommand {
  @BooleanArgument(help: 'Should the file be removed locally after downloaded?')
  bool removeAfterPut;

  @HelpArgument()
  bool help;

  @override
  void execute(SmartArg parentArguments) {
    if (help == true) {
      print(usage());
      exit(0);
    }

    if ((parentArguments as Args).verbose == true) {
      print('Verbose is on');
    } else {
      print('Verbose is off');
    }

    print('Putting file...');

    if (removeAfterPut == true) {
      print('Removing file on local disk (not really)');
    }
  }
}

@SmartArg.reflectable
@Parser(
  description: 'Example using commands',
  extendedHelp: [
    ExtendedHelp('This is some text below the command listing',
        header: 'EXTENDED HELP')
  ],
)
class Args extends SmartArg {
  @BooleanArgument(short: 'v', help: 'Verbose mode')
  bool verbose;

  @Command(help: 'Get a file from the remote server')
  GetCommand get;

  @Command(help: 'Put a file on the remote server')
  PutCommand put;

  @HelpArgument()
  bool help;
}

void main(List<String> arguments) {
  initializeReflectable();

  var args = Args()..parse(arguments);

  if (args.help == true) {
    print(args.usage());
    exit(0);
  }
}

Features and bugs #

Please send pull requests, feature requests and bug reports to the issue tracker.

1.1.1 #

  • Fixed linting errors from dartanalyzer
  • Updated reflectable to 2.2.1

1.1.0 #

  • Moved from dart:mirrors to source generation using reflectable

1.0.0+1 #

  • Updated description in pubspec.yaml due to pub.dev Maintenance suggestions.

1.0.0 #

  • Initial version

example/smart_arg_example.dart

import 'dart:io';

import 'package:smart_arg/smart_arg.dart';

import 'smart_arg_example.reflectable.dart';

@SmartArg.reflectable
@Parser(
  description: 'Example smart arg application',
  minimumExtras: 1,
  maximumExtras: 1,
  exitOnFailure: true,
  extendedHelp: [
    ExtendedHelp('''
      This is a simple application that does nothing and contains silly arguments. It simply shows
      how the
      smart_arg library can be used.

      No one should really try to use this
      program outside of those interested
      in using smart_arg in their own
      applications.'''),
    ExtendedHelp(
      'This is more extended text that can be put into its own section.',
      header: 'SECTION 2',
    ),
  ],
)
class Args extends SmartArg {
  @Group(
    name: 'Group 1',
    beforeHelp: '''
    This is some long text that explains this section in detail. Blah blah blah
    blah blah blah blah blah. This will be wrapped as needed. Thus, it will
    display beautifully in the console.
  ''',
    afterHelp:
        'This is just a single sentence but even it will be wrapped if necessary',
  )
  @StringArgument()
  List<String> names;

  @StringArgument(
    short: 'r',
    help: 'Report header text',
  )
  String header;

  @FileArgument(
    help: 'Filename to report stats on',
    mustExist: true,
  )
  File filename;

  @Group(
    name: 'Group 2 -- OTHER',
    beforeHelp: 'Help before',
    afterHelp: 'Help after',
  )
  @IntegerArgument(
    help: 'Count of times to say hello',
  )
  int count;

  @DoubleArgument(
    help:
        'Some other silly parameter to show double parsing. This also has a very long description that should word wrap in the output and produce beautiful display.',
  )
  double silly;

  @BooleanArgument(
    short: 'v',
    help: '''Turn verbose mode on.

    This is an example also of using multi-line help text that is formatted
    inside of the editor. This should be one paragraph. I'll add some more
    content here. This will be the last sentence of the first paragraph.

    This is another paragraph formatted very
    narrowly in the code editor. Does it
    look the same as the one above? I sure
    hope that it does. It would make help
    display very easy to implement.
    ''',
    isNegateable: true,
  )
  bool verbose = false;

  @HelpArgument()
  bool help = false;
}

void main(List<String> arguments) {
  initializeReflectable();

  var args = Args()..parse(arguments);

  if (args.help) {
    print(args.usage());
    exit(0);
  }

  print('header  : ${args.header}');
  print('filename: ${args.filename}');
  print('verbose : ${args.verbose}');
  print('count   : ${args.count}');
  print('silly   : ${args.silly}');
  print('names   : ${args.names?.join(', ')}');
  print('extras  : ${args.extras.join(' ')}');
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  smart_arg: ^1.1.1

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter pub get

Alternatively, your editor might support pub get or flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:smart_arg/smart_arg.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
36
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
68
Learn more about scoring.

We analyzed this package on Jan 19, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.0
  • pana: 0.13.4

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.5.0 <3.0.0
path ^1.6.4 1.6.4
reflectable ^2.2.1 2.2.1+1
Transitive dependencies
_fe_analyzer_shared 1.0.3
analyzer 0.39.3 0.39.4
args 1.5.2
async 2.4.0
build 1.2.2
build_config 0.4.1+1
build_daemon 2.1.3
build_resolvers 1.3.1
build_runner_core 4.3.0
built_collection 4.3.2
built_value 7.0.8
charcode 1.1.2
checked_yaml 1.0.2
code_builder 3.2.1
collection 1.14.12
convert 2.1.1
crypto 2.1.4
csslib 0.16.1
dart_style 1.3.3
fixnum 0.10.11
glob 1.2.0
graphs 0.2.0
html 0.14.0+3
http 0.12.0+4
http_multi_server 2.1.0
http_parser 3.1.3
io 0.3.3
js 0.6.1+1
json_annotation 3.0.1
logging 0.11.4
matcher 0.12.6
meta 1.1.8
mime 0.9.6+3
node_interop 1.0.3
node_io 1.0.1+2
package_config 1.1.0
package_resolver 1.0.10
pool 1.4.0
pub_semver 1.4.2
pubspec_parse 0.1.5
quiver 2.1.2+1
shelf 0.7.5
shelf_web_socket 0.2.3
source_span 1.6.0
stack_trace 1.9.3
stream_channel 2.0.0
stream_transform 1.1.0
string_scanner 1.0.5
term_glyph 1.1.0
timing 0.1.1+2
typed_data 1.1.6
watcher 0.9.7+13
web_socket_channel 1.1.0
yaml 2.2.0
Dev dependencies
build_runner ^1.7.2 1.7.3
build_test ^0.10.11
pedantic ^1.8.0 1.9.0
test ^1.6.0