-
Notifications
You must be signed in to change notification settings - Fork 4
Getting Started
npm install shotgun
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.
-
First set up a basic 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 -
Once you have a proper prompt application setup go ahead and install shotgun.
npm install shotgun
-
Require shotgun and instantiate a shell.
var readline = require('readline'), shotgun = require('shotgun'), shell = new shotgun.Shell(); ... -
Now that you have an instance of the shell you can begin to pass the user's value into the
execute()function.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); rl.on('line', function (cmdStr) { shell.execute(cmdStr); rl.prompt(); }); rl.prompt(); -
So far all we've done is pass the user's input on to shotgun and setup an
onDatacallback function that receives adataobject, but we're not yet using it for anything. Thedataobject passed to the callback from shotgun acts as a set of instructions. Depending on the command modules installed the data object could contain a wide variety of properties for you to consume in your application. There are a few default commands that come with shotgun: clear, exit, and help. 'clear' sets a property on the object calledclearDisplay. 'exit' sets a property on the object calledexit. 'help' prints out a bunch of lines showing the commands that are available. Thelineproperty on thedataobject represents a single line of text. This is how shotgun stays UI agnostic because the app using shotgun can iterate over these properties and take action based on the values provided. Let's write some code to handle each of these situations: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); // Configure shotgun. shell.onData(function (data) { if (data.clearDisplay) console.log('\u001B[2J\u001B[0;0f'); if (data.line) console[data.line.type](data.line.text); if (data.exit) { rl.close(); process.exit(); } }); rl.on('line', function (cmdStr) { shell.execute(cmdStr); rl.prompt(); }); rl.prompt();In the above example we do several things with the result. First we check if
clearDisplayis true. If it is then we clear the console display using ASCII control sequences. Next we check ifexitis true and if it is then we close the readline interface and exit the current process. Lastly we see if there is alineproperty; if so, then we use thelineobject's properties to determine how to display the text. Thelineobject has atypeproperty, atextproperty, and anoptionsproperty. Obviouslytextcontains the text for that line; by defaulttypecontains either 'log', 'warn', 'error' as it's value, but it is possible to write lines with your own custom types. You can do whatever you choose with that value but in this example I decided to map that to the functions with the same name onconsole, passing inline.textto be displayed. -
We're almost done but there is one more piece we need to include. To maintain state across executions shotgun provides a context API. This context contains information that allows shotgun to know if it was prompting the user for a value among other things. You can even use this object yourself to maintain your own custom states for your users, such as authentication information.
By default shotgun maintains its own internal context. This works great for plain console applications where at most one user will be using the application at a time. However, if your application gets more complicated then you will likely want to store the context object yourself so you can maintain different context objects per user. For example, in a web application you would either store the context object in the user's session as a session variable or you would pass the object to the client to be stored in the browser and re-transmitted with the user's next input.
To configure a custom context object in our sample app we will create a context variable and use that as our context storage. Whenever shotgun manipulates the context object it will invoke an onContextSave callback function. Note: This is just an example. As I said earlier, in plain console applications you don't even have to do this because it will maintain its own internal context by default.
var readline = require('readline'),
shotgun = require('../index'),
shell = new shotgun.Shell(),
context = {}; // Declare empty context object.
// Create interface that reads from console and outputs to console.
var rl = readline.createInterface(process.stdin, process.stdout);
// Configure shotgun.
shell
// Handle the onContextSave callback and save the context to our custom variable.
.onContextSave(function (updatedContext) {
context = updatedContext;
})
// This callback is fired every time shotgun sends data back to your application.
.onData(function (data) {
if (data.clearDisplay) console.log('\u001B[2J\u001B[0;0f');
if (data.line)
console[data.line.type](data.line.text);
if (data.exit) {
rl.close();
process.exit();
}
});
rl.on('line', function (cmdStr) {
shell.execute(cmdStr, context);
rl.prompt();
});
rl.prompt();
Now our context object is available to us and we can store it however we wish. To ensure that shotgun is operating under the correct context, simply pass in our context variable as the second parameter to shell.execute(). This is how shotgun maintains state in stateless architectures such as the web.
That's it, you're done with your first little shotgun app!