Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

working on a new API for commands that creates less redundant code #368

Merged
merged 20 commits into from
Feb 14, 2016

Conversation

bcoe
Copy link
Member

@bcoe bcoe commented Feb 7, 2016

I'm working on a new API for commands that makes writing them less redundant:

  • commands now accept two functions a builder for describing command-specific help, and a handler that will get argv passed to it.
  • the concept of global options is being introduced, to eliminate the need for setting the same option over and over again on each command.
  • positional argument parsing: foo <foo> [bar] is being introduced.
  • Builder/Handler Pattern.

The definition of commands has now been split into a:

  • builder: which is used to describe a command.
  • handler: which is used to handle a command when it is invoked.
var argv = require('yargs')
  .command(
    'push', 
    'push to a URL', 
    function (yargs) {
      // build command specific yargs object.
    },
    function (argv) {
      // handle the parsed options.
   })
   .help('help')
  .argv
  • Providing a Module For Commands

I would like to make it so that you could also provide a module to command, you would write a module like this:

exports.builder = function (yargs) {
  return yargs.option('f', {})
}
exports.handler = function (argv) {
// do something with argv.
}

And would provide it to a command like this:

yargs.command('foo', 'my awesome foo command', require('./test-module')).

I think this is pretty killer, and splitting out the builder and handler makes this possible what do you think @nexdrew?

  • Global Options

You can now specify global options using .global() or the global: true shorthand on options.

These options will not be reset when passed to commands, by default help, version, are treated this way (since this is the behavior folks usually want).

  • Parsing Positional Arguments

see: #363, #362

@bcoe bcoe force-pushed the command-improvements branch from 650a021 to 8c51940 Compare February 7, 2016 19:07
it('defaults to appropriate version # when yargs is installed normally', function (done) {
testCmd('./normal-bin.js', [ '--version' ], function (buf) {
buf.should.match(/9\.9\.9/)
if (!isWindows()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need a new dependency for that? Why not just use process.platform !== 'win32'?

@bcoe bcoe changed the title [WIP] working on a new API for commands that creates less redundant code working on a new API for commands that creates less redundant code Feb 13, 2016
@wraithan
Copy link

Big fan of the new style, looking forward to taking advantage of it in a couple little tools I've written.

Mostly it is the module style that I'll be using, will be able to more cleanly divide up my code. The globals I'll probably lean on in very simple tools and stay away from in more complex ones.

})
.help()
.argv
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it may be better to stick with the same structure of an example that we use above, i.e:

var argv = require('yargs')
  .command('get', 'make a get HTTP request', {
    url: {
      default: 'http://yargs.js.org/'
    }
  })
  .help()
  .argv

The change in structure might confuse people (even though you mention that this is a yargs instance), and knowing people don't always read text and skip to code, we might run into some trouble :o What do you think?

Edit: same goes for L484-487

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lrlna I've updated the documentation for command modules which I think are the most elegant approach we can direct people towards.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bcoe 🆒, I like it.

bcoe added a commit that referenced this pull request Feb 14, 2016
working on a new API for commands that creates less redundant code
@bcoe bcoe merged commit 618abda into 4.x Feb 14, 2016
@nexdrew nexdrew deleted the command-improvements branch February 15, 2016 19:59
@pscanf
Copy link

pscanf commented Feb 21, 2016

@bcoe a maybe-trivial clarification on the API: the intended purpose of the handler function is to kick off my command logic execution, correct?

Example:

#!/usr/bin/env node

import yargs from 'yargs';
import do_a from './do_a.js';
import do_b from './do_b.js';

yargs
  .command('do_a', 'Does A', {/* a options */}, do_a)
  .command('do_b', 'Does B', {/* b options */}, do_b);

(I ask because in the example you save in a variable the argv object, which I guess has little use at that point though)

@pluma
Copy link

pluma commented Mar 9, 2016

Is there any way to specify the equivalent of the last argument to demand (i.e. an error message) when defining commands with positional arguments this way? The default error message is pretty meaningless for mortals.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants