Composing steps

by andrewdavey

HTML

<ul id="log">
    
</ul>

JavaScript

function define(type, fn) {
    return function() {
        var args = Array.prototype.slice.apply(arguments);
        return new type(fn, args);
    }
};

function Step(func, args) {
    this.func = func;
    this.args = args;
}
Step.prototype.run = function(context, done, fail) {
    try {
        this.func.apply(context, this.args);
        done();
    } catch (e) {
        fail(e);
    }
};

function AsyncStep(func, args) {
    this.func = func;
    this.args = args;
}
AsyncStep.prototype.run = function(context, done, fail) {
    try {
        context.done = done;
        context.fail = fail;
        this.func.apply(context, this.args);
    } catch (e) {
        fail(e);
    }
};

function Assertion(func, args) {
    this.func = func;
    this.args = args;
}
Assertion.prototype.run = function(context, done, fail) {
    try {
        var result = this.func.apply(context, this.args);
        if (result) {
            done(result);
        } else {
            fail(result);
        }
    } catch (e) {
        fail(e);
    }
};


var say = define(Step, function(msg) { log(msg); });

var wait = define(AsyncStep, function(ms) {
    setTimeout(this.done, ms);
});

var answer = 42;
var answerIs = define(Assertion, function(number) { return answer === number; });

    
var steps = sequence([
    say("hello"),
    wait(500),
    say("world")
]);

var assertions = tryAll([
    answerIs(42),
    answerIs(42)
]);

sequence([steps, wait(500), assertions])
.run(
    {}, 
    function(result) {
        log(JSON.stringify(result));
    },
    function(results) {
        log("Some failed: " + JSON.stringify(results));
    }
);


function sequence(actions) {
    return {
        run: function(context, done, fail) {
            actions.reduceRight(
                function(next, action) {
                    return function() {
                        action.run(context, next, fail);
                    }
                },
                done
            )();
        }
   ...