Skip to content
This repository has been archived by the owner on Jul 14, 2019. It is now read-only.

Getting Started

Alex Ford edited this page Mar 3, 2014 · 17 revisions

<< home


Installation

npm install shotgun

Basic Setup

To use shotgun you simply require it and create an instance of the shell.

var shotgun = require('shotgun');
var shell = new shotgun.Shell();

The shell optionally accepts an options object. One of the options available is cmdsDir which is a path to the directory containing your custom command modules (relative to the current working directory). If no directory is specified then 'shotgun_cmds' is used by default. Shotgun will automatically read in and require() all node modules in the specified directory and it will plug them into the framework as commands as long as they expose the required properties and functions.

Once you have an instance of the shotgun shell you are ready to get started building your application. You can build any UI application around shotgun that you wish. The simplest application is just a basic console app so that's what we'll setup here.

  1. First set up a basic terminal app to continually get a value from the user.

    var readline = require('readline');
    
    // Create interface that reads from console and outputs to console.
    var rl = readline.createInterface(process.stdin, process.stdout);
    rl.setPrompt("> ");
    
    rl.on('line', function (cmdStr) {
        console.log("Echo: %s", cmdStr);
        rl.prompt();
    });
    
    rl.prompt();

    So far we haven't done anything with shotgun. We've just put together a small app that continually asks the user for input and then prints that input to the console.

    > test
    Echo: test

  2. Once you have a proper prompt application setup go ahead and install shotgun.

    npm install shotgun

  3. Require shotgun and instantiate a shell.

    var readline = require('readline'),
        shotgun = require('shotgun'),
        shell = new shotgun.Shell();
  4. Now that you have an instance of the shell you can setup some event listeners on the shell and pass the user's input into the execute() function. shell.execute takes three arguments:

    ####cmdStr

    The user-provided input (usually a command name followed by options and arguments).

    ####contextData (optional)

    This object is used to maintain state within shotgun. You'll learn about this in the next wiki article linked at the bottom of this one. ####options (optional)

    Simple hash whose properties will be added to properties passed in via the user input. If the user passes in an option and the same option is found in the options argument then the user's value will be overridden with the value from the options hash.

    var readline = require('readline'),
        shotgun = require('../index'),
        shell = new shotgun.Shell();
    
    // Create interface that reads from console and outputs to console.
    var rl = readline.createInterface(process.stdin, process.stdout);
    
    shell
        .on('log', function (text, options) {
            console[options.type](text);
        })
        .on('clear', function () {
            console.log('\u001B[2J\u001B[0;0f');
        })
        .on('exit', function () {
            rl.close();
            process.exit();
        })
        .on('done', function () {
            rl.prompt();
        })
        .on('error', console.error.bind(console));
    
    rl.on('line', function (cmdStr) {
        shell.execute(cmdStr);
    });
    
    rl.prompt();

    By default shotgun includes three command modules: clear, exit, and help. One of the most common events that you will emit from your custom command modules is log via the shell.log helper function so the first event listener we configure is log. You can see that it accepts a text argument and an options argument. This event is dead simple: text is just the string to display to the user and options is just a simple hash with properties telling you how you might want to format the text. I say "might" because the properties on this object can usually be ignored, and sometimes you have no choice if your application's interface doesn't support the formatting specified there. For example, options.italics might be true but we have no way to display italics in the terminal so we'd have to ignore that setting or do some other kind of formatting in place of italics.

    The clear command module emits a clear event so we need to set up an event handler to handle that situation. (Note: The weird characters in the string we log to the console just clears the terminal window.) Keep in mind that while the clear command will call the clear event to clear the terminal window the clear event could be invoked from any command module, and often is. For instance, your custom command might need to display a lot of data and you may not want to simply append that data to the terminal window; you might invoke the clear event before logging your data so that it is the only thing displayed.

    The exit command module also emits an event exit. Here all we do is kill our prompt application and end the process. Easy right? Just like clear you could invoke the exit event from anywhere, though this one is rarely invoked outside of the actual exit command module itself.

    The done event is fired when shotgun has finished the current execution. In many cases your command modules will perform asynchronous behavior. The only way we can be certain that we're ready to prompt the user for input again is via the done event. If you put rl.prompt() after the call to shell.execute you would quickly find that your program doesn't wait for asynchronous commands to finish before prompting the user for further input. This can cause all sorts of unforeseen behavior, so don't think that shotgun has finished until the done event fires.

    Finally, the last event we handle is error. If shotgun ever blows up, this is where the error will go. You don't have to handle this event if you don't want to, but keep in mind that if you don't handle errors then shotgun will throw them and your application will halt. I don't believe in hiding errors; I like to encourage users to handle them gracefully. If you really want to hide errors then simple handle them and do nothing in the handler.

That's it, you're done with your first little shotgun app!


Next up: Command Contexts >>

Clone this wiki locally