Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules/
.nyc_output
node_modules

npm-debug.log
17 changes: 15 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
sudo: false
os: linux
language: node_js
node_js:
- 0.10
- 0.8
- "0.10"
- "0.11"
- "0.12"
- "4"
- "5"
env:
matrix:
- TEST_SUITE=unit
matrix:
include:
- node_js: 4
env: TEST_SUITE=lint
script: npm run $TEST_SUITE
87 changes: 34 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,90 +1,71 @@
# suppose

Node.js - suppose
=================
[![NPM Package](https://img.shields.io/npm/v/suppose.svg?style=flat-square)](https://www.npmjs.org/package/suppose)
[![Build Status](https://img.shields.io/travis/jprichardson/node-suppose.svg?branch=master&style=flat-square)](https://travis-ci.org/jprichardson/node-suppose)
[![Dependency status](https://img.shields.io/david/jprichardson/node-suppose.svg?style=flat-square)](https://david-dm.org/jprichardson/node-suppose#info=dependencies)

<!--
[![build status](https://secure.travis-ci.org/jprichardson/node-suppose.png)](http://travis-ci.org/jprichardson/node-suppose)
-->
[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard)

Have you ever heard of the command line program [expect][1]? Basically, `expect` allows you to automate command line programs. `suppose` is a programmable Node.js module that allows the same behavior.
Have you ever heard of the command line program [expect][1]? Basically, `expect` allows you to automate command line programs. `suppose` is a programmable [Node.js][2] module that allows the same behavior. (*not exactly same, just based on ideas from expect*)

## Why?

From the [expect wikipedia][1] page, you can see many examples of `expect` scripts automating tasks such as `telnet` or `ftp` sessions. Now you can easily write [Node.js][2] scripts to do the same. This may be most beneficial during testing.

Why?
----

From the [expect wikipedia][1] page, you can see many examples of `expect` scripts automating tasks such as `telnet` or `ftp` sessions. Now you can easily write Node.js scripts to do the same. This may be most beneficial during testing.



Installation
------------

npm install suppose

## Installation

```shell
npm install suppose
```

Example
------
## Example

Automate the command `npm init`, which initializes a new npm module.

```javascript
```js
var suppose = require('suppose')
, fs = require('fs')
, assert = require('assert')
var fs = require('fs')
var assert = require('assert')

process.chdir('/tmp/awesome');
process.chdir('/tmp/awesome')
fs.writeFileSync('/tmp/awesome/README.md', 'READ IT')
// debug is an optional writeable output stream
suppose('npm', ['init'], {debug: fs.createWriteStream('/tmp/debug.txt')})
suppose('npm', [ 'init' ], { debug: fs.createWriteStream('/tmp/debug.txt') })
.when(/name\: \([\w|\-]+\)[\s]*/).respond('awesome_package\n')
.when('version: (1.0.0) ').respond('0.0.1\n')
// response can also be the second argument to .when
.when('description: ', "It's an awesome package man!\n")
.when('entry point: (index.js) ').respond("\n")
.when('description: ', 'It\'s an awesome package man!\n')
.when('entry point: (index.js) ').respond('\n')
.when('test command: ').respond('npm test\n')
.when('git repository: ').respond("\n")
.when('git repository: ').respond('\n')
.when('keywords: ').respond('awesome, cool\n')
.when('author: ').respond('JP Richardson\n')
.when('license: (ISC) ').respond('MIT\n')
.when('ok? (yes) ' ).respond('yes\n')
.on('error', function(err){
console.log(err.message);
.when('ok? (yes) ').respond('yes\n')
.on('error', function (err) {
console.log(err)
})
.end(function(code){
var packageFile = '/tmp/awesome/package.json';
fs.readFile(packageFile, function(err, data){
var packageObj = JSON.parse(data.toString());
console.log(packageObj.name); //'awesome_package'
})
.end(function (code) {
var packageFile = '/tmp/awesome/package.json'
var packageObj = JSON.parse(fs.readFileSync(packageFile))
console.log(packageObj.name) // 'awesome_package'
})
```

`.respond()` may be called any number of times after `.when()`. Each response
will be sent in the order defined when the condition matches. Once all
`.respond()` may be called any number of times after `.when()`. Each response will be sent in the order defined when the condition matches. Once all
conditions and responses are defined, call `.end()` to begin execution.

## Contributors

Contributors
------------
- [*] [Philipp Staender](https://github.com/pstaender)


License
-------

(MIT License)

Copyright 2012-2013, JP Richardson
- [Philipp Staender](https://github.com/pstaender)

## License

MIT

[1]: http://en.wikipedia.org/wiki/Expect


[2]: http://nodejs.org/
[aboutjp]: http://about.me/jprichardson
[twitter]: http://twitter.com/jprichardson
[procbits]: http://procbits.com
[gitpilot]: http://gitpilot.com

2 changes: 2 additions & 0 deletions browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'use strict'
module.exports.Stream = require('./lib/stream')
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use strict'
module.exports.Process = require('./lib/process')
module.exports.Stream = require('./lib/stream')
76 changes: 76 additions & 0 deletions lib/process.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
var EventEmitter = require('events')
var spawn = require('child_process').spawn
var inherits = require('inherits')

var SupposeStream = require('./stream')

function SupposeProcess (command, args, options) {
EventEmitter.call(this)

if (!Array.isArray(args)) {
options = args
args = undefined
}

this._command = command
this._args = args || []
this._options = options || {}

this._debug = this._options.debug
if (this._debug === true) this._debug = process.stderr

this._supposeStream = new SupposeStream(this._debug)
this._supposeStream.on('error', this.emit.bind(this, 'error'))

this._exe = null
}

inherits(SupposeProcess, EventEmitter)

SupposeProcess.prototype.when = function (expect, response) {
this._supposeStream.when(expect, response)
return this
}

SupposeProcess.prototype.respond = function (response) {
if (typeof response === 'function') {
var self = this
var _response = response
response = function () {
var args = [].slice.call(arguments)
args.unshift(self._exe)
_response.apply(self, args)
}
}

this._supposeStream.respond(response)
return this
}

SupposeProcess.prototype.end = function (callback) {
this._exe = spawn(this._command, this._args, this._options)

if (this._debug) {
var cmdString = this._command + ' ' + this._args.join(' ') + '\n'
this._debug.write(cmdString, 'utf8')
for (var i = 0; i < cmdString.length; ++i) this._debug.write('-')
this._debug.write('\n')
}

// Empty write signals SupposeStream that input has started and .when()
// will not be called again so it can end output early where possible.
this._supposeStream.write('')

this._exe.stdout.pipe(this._supposeStream).pipe(this._exe.stdin)

var self = this
this._exe.stderr.on('data', function (data) {
self.emit('error', new Error(data.toString()))
})

this._exe.on('exit', callback.bind(this))

return this._exe
}

module.exports = SupposeProcess
80 changes: 80 additions & 0 deletions lib/stream.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
var Transform = require('stream').Transform
var inherits = require('inherits')

function SupposeStream (debug) {
Transform.call(this)

this._debug = debug

this._expects = []
this._condition = null
this._responses = null
this._text = ''
this._needNew = true
this._sentEOF = false
}

inherits(SupposeStream, Transform)

SupposeStream.prototype._transform = function (chunk, encoding, callback) {
if (this._debug) this._debug.write(chunk)

this._text += chunk.toString()
if (this._needNew) {
var expect = this._expects.shift()
this._condition = expect && expect.condition
this._responses = expect && expect.responses

if (!expect && !this._sentEOF) {
// this.expects was always empty
this.push(null)
this._sentEOF = true
}

this._needNew = false
}

var match
if (typeof this._condition === 'string') {
match = this._text.slice(-this._condition.length) === this._condition
} else if (this._condition instanceof RegExp) {
match = this._text.match(this._condition)
}

if (match) {
match = Array.isArray(match) ? match.slice(1) : []

this._text = ''
this._needNew = true

this._responses.forEach(function (response) {
if (typeof response === 'function') {
response.apply(this, match)
} else {
this.push(response)
if (this._debug) this._debug.write(response, 'utf8')
}
}, this)

if (this._expects.length === 0) {
this.push(null)
this._sentEOF = true
}
}

callback()
}

SupposeStream.prototype.when = function (condition, response) {
this._expects.push({ condition: condition, responses: [] })
if (response) this.respond(response)
return this
}

SupposeStream.prototype.respond = function (responses) {
var expect = this._expects[this._expects.length - 1]
expect.responses = expect.responses.concat(responses)
return this
}

module.exports = SupposeStream
Loading