Skip to content

Commit

Permalink
Initial working workshop
Browse files Browse the repository at this point in the history
  • Loading branch information
mikaelbr committed Aug 19, 2014
0 parents commit 6a75556
Show file tree
Hide file tree
Showing 9 changed files with 206 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
.DS_Store
node_modules/
27 changes: 27 additions & 0 deletions exercises/1_intro_to_workshop/exercise.js
@@ -0,0 +1,27 @@
'use strict';

var verify = require("../../verify.js");

var run = {
input: void 0,
expect: function (stream, ex, done) {
var expected = 6;
stream
.fold(0, function (a, b) {
return a + b;
})
.onValue(function (val) {
done(val !== expected);
});
}
};


var testing = {
'Should emit values that sum up to 6': {
input: run.input,
shouldbe: run.expect
}
};

module.exports = verify(testing, run);
31 changes: 31 additions & 0 deletions exercises/1_intro_to_workshop/problem.md
@@ -0,0 +1,31 @@
# How to do exercises

Each exercise will have different solutions to solve.
Create a file with your solution and try to run it
against the verifier.


## Problem description

Create a file that returns an event stream emitting values
that sum up to `6`. See the Bacon.js API for how to
create new event sources.


## Template

All of your solutions must follow this template:

```js
// include the Bacon.js library
var Bacon = require('baconjs');

var streamGenerator = function(input1, input2, ...) {
// return resulting stream
};

// expose the stream generator as a module method
module.exports = streamGenerator;
```

Inputs may vary in different exercises
5 changes: 5 additions & 0 deletions exercises/1_intro_to_workshop/solution/solution.js
@@ -0,0 +1,5 @@
var Bacon = require('baconjs');

module.exports = function () {
return Bacon.sequentially(100, [1, 2, 3]);
};
1 change: 1 addition & 0 deletions exercises/menu.json
@@ -0,0 +1 @@
["1_intro_to_workshop"]
15 changes: 15 additions & 0 deletions index.js
@@ -0,0 +1,15 @@
#!/usr/bin/env node

const workshopper = require('workshopper');
const join = require('path').join;

workshopper({
name: 'bacon-love',
title: 'A Workshop for Functional Reactive Programming',
exerciseDir: join(__dirname, 'exercises'),
appDir: __dirname,
menu: {
fg: 'white',
bg: 'black',
}
});
18 changes: 18 additions & 0 deletions package.json
@@ -0,0 +1,18 @@
{
"name": "bacon-love",
"version": "1.0.0",
"description": "A Nodeschool type workshop for Functional Reactive Programming and Bacon.js",
"main": "index.js",
"bin": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "MIT",
"dependencies": {
"baconjs": "^0.7.22",
"lodash": "^2.4.1",
"workshopper": "^1.3.2",
"workshopper-exercise": "^1.1.0"
}
}
20 changes: 20 additions & 0 deletions tasks.md
@@ -0,0 +1,20 @@
# Possible tasks for a FRP workshop

## Introductory

1. Create own event streams (all sources)
2. Subscribers
3. Filter -> Map -> Log based on given event stream as input
4. Fold/Scan
5. Properties vs EventStreams
6. Merge/Combine

## Advanced

1. Combination of multiples as templates
2. Sampling
3. Throttling/Delays
4. Flatmaps


## Beyond
87 changes: 87 additions & 0 deletions verify.js
@@ -0,0 +1,87 @@
'use strict';

var path = require('path');

var _ = require('lodash');
var Bacon = require('baconjs');
var exerciser = require('workshopper-exercise');
var filecheck = require('workshopper-exercise/filecheck');
var execute = require('workshopper-exercise/execute');

module.exports = function (tests, testRun) {
var exercise = _.compose(execute, filecheck)(exerciser());

exercise.addProcessor(function (mode, callback) {
var isRunMode = mode === 'run', self = this, passed = true, usersolution;
var usersolution;

try{
usersolution = require(path.resolve(process.cwd(), this.args[0]));
} catch (e) {
var message = (e.code !== 'MODULE_NOT_FOUND'
? 'Could not find your file. Make sure the path is correct.'
: 'You need to install all of the dependencies you are using in your solution (e.g. "npm install baconjs")')

this.emit('fail', message);
return callback(null, false);
}

if(typeof usersolution !== 'function'){
this.emit('fail', 'You should always return a function using module.exports.');
return callback(null, false);
}

if(isRunMode) {
return run(self, usersolution, testRun, callback);
}

var done = _.after(tests.length, function() {
callback(null, passed);
});

_.each(tests, function (item, element) {
run(self, usersolution, testRun, element, function (err, success) {
if (!success) passed = false;
done();
});
});
});

return exercise;
};

function run (exercise, fn, item, desc, cb) {
if (typeof desc === 'function') {
cb = desc;
desc = void 0;
}
desc = desc || 'Test run';

var stream;
try {
stream = fn.apply(fn, garanteeArray(item.input));
} catch (e) { }

if (!isStream(stream)) {
exercise.emit('fail', 'The exported function should always return an event stream or property.');
return false;
}

item.expect(stream, exercise, function (err) {
if (err) {
exercise.emit('fail', desc);
return cb(null, false);
}

exercise.emit('pass', desc);
return cb(null, true);
});
}

function isStream (obj) {
return obj instanceof Bacon.Property || obj instanceof Bacon.EventStream;
}

function garanteeArray (input) {
return _.isArray(input) ? input : [input];
}

0 comments on commit 6a75556

Please sign in to comment.