Machinepacks are bundles of related machines. They might be unified by the API they talk to (e.g. Stripe) or their purpose (e.g. Passwords). It's really up to you! The important thing to remember is that machinepacks are just a versioned, organizational unit you can publish and install.
For example, as of February 2015, machinepack-github contains 11 machines; it supports everything from fetching basic metadata about a particular GitHub user, to listing repo activity, to creating a new repo altogether. The machinepack can be installed and required from your Node.js code like any other npm
module:
var Github = require('machinepack-github');
// Fetch metadata about a repository on GitHub.
Github.getRepo({
repo: 'sails',
owner: 'balderdashy',
}).exec({
// An unexpected error occurred.
error: function (){
},
// OK.
success: function (result){
console.log('Got:\n', result);
},
});
In the process of using machines for the past year or so, the core team behind this project and specification created a couple of tools to make machines easier to work with. The two we'll be using in this walkthrough are machinepack
and generator-machinepack
. Both are completely optional, but also readily available on NPM.
For your convenience, there is a Yeoman generator for creating machinepacks. You will likely only use this tool every now and then, but it's worth it to get you off the ground running.
The Yeoman generator (generator-machinepack
) requires Yeoman. If you don't already have Yeoman globally installed, you'll want to do that before proceeding:
$ npm install -g yo
To install the generator:
$ npm install -g generator-machinepack
machinepack
CLI toolThe machinepack
tool was designed to solve a few key annoyances of building machines. It provides the capability of testing machines from the command-line with an interactive prompt, a readily-accesible manpage for checking a pack's metadata and machines, as well as shortcuts for simple operations like adding or removing machines to a pack. If you're like me, and working with machines on a regular basis, you'll find it indispensible.
To install the machinepack
command-line interface from NPM:
$ npm install -g machinepack
Note: If you run into install issues, try
$ sudo
.
I ran across an interesting API from Klout. Klout uses social media analytics to rank people based upon their social influence via a Klout Score. So we'll create a couple of machines that will return a person's Klout ID and Klout score.
To begin, we'll generate a bare bones machinepack by typing:
$ yo machinepack
You'll be prompted for a "friendly name". By entering "Klout", the machinepack name will become machinepack-klout
.
_-----_
| | .--------------------------.
|--(o)--| | Welcome to the |
`---------´ | Machinepack generator! |
( _´U`_ ) '--------------------------'
/___A___\
| ~ |
__'.___.'__
´ ` |° ´ Y `
? What would you like to use as the "friendly name" for your machinepack?
(e.g. "Passwords" or "Twitter")
Klout
Next, you'll be asked to provide a description.
? Describe this machinepack in 80 characters or less.
(e.g. "Communicate with the Github API to get repos, commits, etc.")
(Work with klout.) Communicate with the Klout API to get Ids, Klout Scores, etc.
The generator gives you the option to create an example machine. Let's go ahead and type y
for yes and generate the example machine.
? Want me to create an example machine (`say-hello.js`) to help you get started? (y/N) y
Finally, you'll be prompted to specify whether to put this example machine in a new folder within the machinepack, or at the root of the machinepack. Let's just press enter to use the default, and have the generator create a folder for us.
? Where should this new machinepack be generated?
❯ In a new folder (/Users/jgalt/Development/machinepack-klout)
Within the current directory (/Users/jgalt/Development/)
All of the necessary structure will be created including installing any dependencies.
First, cd
into your new machinepack folder.
$ cd machinepack-klout
Now let's take a look at the example machine:
$ machinepack ls
You should see the following in your terminal window:
There is only 1 machine in this machinepack.
=============================================
• say-hello
say-hello
do?We could create a node script that requires the machine programatically and then calls .exec()
on it, but that sort of sucks. Alternatively, we could use the node REPL, but... still sort of sucks.
Instead, we'll take advantage of the most powerful feature of the machinepack
command-line tool- the ability to execute a machine interactively. To run a machine from the command-line:
$ machinepack exec say-hello
If the machine has any required inputs, you'll be prompted to enter a value for each of them. In this case, you'll be asked to enter a "name":
? Please enter the name of the person that will be sent the hello message.
name: John
Hello John, your secret code is 0.8229460262227803
________________________________________________________________˛
Klout.sayHello()
» name "John"
________________________________________________________________¸
|
•
The machine triggered its success exit and returned a value:
{ numLettersInName: 4, secretCode: '0.8229460262227803' }
Adding a machine to an exisitng pack is simple. From the root directory of your machinepack, run:
$ machinepack add
You'll be prompted for a "friendly name":
? What would you like to use as the "friendly name" for your new machine?
(e.g. "Get auth token" or "Delete account")
Get Klout iD
(Don't worry if you mess up, you can always change this later)
The string you enter will be used as the friendlyName
for the new machine, and the machine's identity
will also be inferred from it automatically. For example, if you enter "Get Klout id", you'll end up with a file in your machines folder named get-klout-id
. In userland, you'll be able to call this machine as the .getKloutId()
method on the machinepack. This method name is determined by converting the dash-delimited identity
into camel-case.
Next, you'll be asked for a description
. Make sure you type something less than 80 characters long, and in the imperative mood (e.g. "Delete all..." not "Deletes all..."). This is important for consistency and proper grammar and punctuation in the generated documentation.
? Describe this machine in 80 characters or less.
(e.g. "List all Twitter followers for a particular account.")
Get the Klout id for a user given her Twitter screen name.
We're not going to provide an optional extended description, so we'll press enter to skip the prompt. When we're all done, you should see the following message:
New machine (`get-klout-id`) successfully added to machinepack.
Not too shabby, right? But before we celebrate, let's make sure it worked. When you run machinepack ls
you should see:
There are 2 machines in this machinepack:
=============================================
• get-klout-id
• say-hello
mp info
Before we move on, I'd like to add one more useful strategy to your bag of tricks. From the root of your machinepack, give this a go:
$ machinepack info
The following information should be displayed:
Klout -- Communicate with the Klout API to get Ids, Klout Scores, etc.
INSTALLATION
npm install [email protected]^0.1.0 --save
USAGE
var Klout = require('machinepack-klout');
AVAILABLE METHODS
Klout.sayHello() (say-hello)
Klout.getKloutId() (get-klout-id)
The mp info
utliity is a great way to get a quick reminder of what's in the pack you're looking at. It's particularly helpful when pulling down a pack you haven't worked with in a few weeks/months/years/etc.
You can follow along with a walkthrough where we implement a complete machine (.getKloutId()
) here. By the end of that guide, you should have a solid mental model for how and why machines work the way they do, as well as a working machine you can immediately start using as a copy+paste example. When you feel confident you've got a handle on how machines work and you're ready to learn how to publish a machinepack, continue on to the next section.
First, remove the sample say-hello
machine. You could manually delete machines/say-hello.js
, then remove the machine from the list in your package.json file. But that's kind of annoying. Luckily our old friend the command-line tool includes a helper script just for occasions like these:
$ mp rm say-hello
While we're at it, let's give our code one last pass to see if there's anything else we don't want to publish to the whole world. Looks like the yeoman generator created an extraneous file, helpfully titled "DELETE_THIS_FILE.md". Let's delete that:
$ rm DELETE_THIS_FILE.md
Next, we'll update the package.json
file with the URL of the GitHub repo where our code is hosted:
"repository": {
"type": "git",
"url": "https://github.com/irlnathan/machinepack-klout.git"
},
This is a good idea with any node module, but for us it's especially important since it will allow node-machine.org to display a "View Source" button on the manpage for your machinepack, and for each of its machines.
Finally, now that we're all ready to go, we'll create a git tag and a commit message for the very first version of our machinepack, v1.0.0. Once again, there is a helpful tool that does this for us; only this time, it's npm itself:
$ npm version major
Confused about what's going on here? You can learn more about semantic versioning, or "semver" on semver.org.
Ok now push that up:
$ git push && git push --tags
And publish v1.0.0 of your machinepack to npm:
$ npm publish
Of course since machinepack-klout
already exists, you won't be actually be able to publish it to NPM. But you get the idea.
By the way, if you haven't published a module to NPM before, don't worry-- it's super easy. Just sign up on NPM's website, then log in from the command-line using
npm login
. After that, if you try runningnpm publish
again, you should have better results.
Congratulations on creating your first machinepack! There are hundreds of machines already published and available on NPM, but there is still plenty of work to do. If you can imagine it implemented in a Node module, you can build it as a machine. Go forth and code... and good luck.