Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

editable string output for lesson select/pass #4

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a9665e1
reroute solution verifing
Dec 22, 2013
ebad9de
update deps, new msee version & usage
rvagg Jan 10, 2014
90463ef
@0.7.0 better markdown formatting
rvagg Jan 10, 2014
34c2507
Merge branch 'master' of https://github.com/rvagg/workshopper into ve…
Jan 20, 2014
2c78952
edit text that prints after pass
Jan 20, 2014
40094cf
edit text printed when challenge not passed
Jan 20, 2014
9c07c3a
edited help menu text
Jan 20, 2014
d567274
add line to bottom print menu
Jan 20, 2014
df85ebb
remove line
Jan 20, 2014
8338f34
edit commands in help
Jan 28, 2014
5274a5e
new packagejson
Jan 28, 2014
d97af6b
add server option and open files option
Jul 9, 2014
8d2990a
bump ver, be verbose
Jul 10, 2014
0e89d96
change footer
Aug 17, 2014
4e689af
add support for languages
Oct 13, 2014
7247e7c
bump ver
Oct 13, 2014
eb0b41a
fix path generation
Oct 13, 2014
0128192
bump ver
Oct 13, 2014
9304f9a
improve instructions
Oct 17, 2014
94a6b23
bump ver
Oct 17, 2014
1f23110
update .gitignore
Aug 13, 2015
c0e941a
trying to clean up what gets printed to the console on pass, so anyon…
Aug 13, 2015
00f9aad
update stuff so default strings can be overridden
Aug 14, 2015
bbac9e0
adding customizable config
Aug 14, 2015
5f6647a
0.1.0
Aug 14, 2015
9bdcf31
update to allow future workshop creators build workshops with the abi…
Aug 15, 2015
cd33cfe
update readme
Aug 15, 2015
46767a7
clean up readme / workshopper js
Aug 15, 2015
1a4434e
merge
Aug 15, 2015
ec8d2ae
clean up some merge conflicts I forgot
Aug 17, 2015
5d1f938
add a }
Aug 17, 2015
acd9aed
rudimentary start for html output
Sep 21, 2015
89b4e27
add shelljs module so cat/echo commands easily print html example
Sep 21, 2015
20c3730
add reset function to clear completed lessons
Sep 28, 2015
92e4052
show our example on last lesson complete also
Sep 29, 2015
82d229f
update helpfile
Sep 29, 2015
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
15 changes: 14 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
node_modules
.idea
*.iml
npm-debug.log
dump.rdb
node_modules
results.tap
results.xml
npm-shrinkwrap.json
.DS_Store
*/.DS_Store
*/*/.DS_Store
._*
*/._*
*/*/._*
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Create a new Node project, add a `"bin"` that looks something like this:

const Workshopper = require('workshopper')
, path = require('path')
, strings = require('./strings')

Workshopper({
name : 'learnyounode'
Expand All @@ -29,6 +30,7 @@ Workshopper({
, helpFile : path.join(__dirname, 'help.txt')
, prerequisitesFile : path.join(__dirname, 'prerequisites.txt')
, creditsFile : path.join(__dirname, 'credits.txt')
, strings : strings
}).init()
```

Expand All @@ -40,6 +42,20 @@ The `'prerequisitesFile'` option is optional but if you supply one, users will g

The `'creditsFile'` option is optional but if you supply one, users will get the contents of this file when they type `app credits` (where 'app' is your workshop application name). This file is intended to give credit to those who have added or assisted in creating the exercises. They will also see a pointer to this whenever they select a new exercise.

`'strings'` points to an optional .json file that allows you to customize what a user sees after selection of a workshopper lesson. If this file is absent, selecting any lesson will also return some stdout that points users to the git-it help guides.

A *strings.json* file looks something like this.

```js
{
"guide": "To view the guide",
"offline": "To view the guide offline, go here:",
"verify": "Type 'workshop-name verify' to check your submission.",
"next": "Type 'workshop-name' to open the menu and move onto the next lesson."
}
```


Create a *menu.json* file in your project that looks something like this:

```js
Expand Down
27 changes: 17 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
{
"name": "workshopper",
"version": "0.6.0",
"name": "workshopper-jlord",
"version": "0.1.0",
"description": "A terminal workshop runner framework",
"main": "./workshopper.js",
"author": "Rod Vagg <[email protected]> (https://github.com/rvagg)",
"contributors": [
"jlord",
"theffner"
],
"repository": {
"type": "git",
"url": "https://github.com/rvagg/workshopper.git"
"url": "https://github.com/jlord/workshopper.git#verify"
},
"license": "MIT",
"dependencies": {
"colors-tmpl": "~0.1.0",
"ecstatic": "^0.5.4",
"lodash": "^3.10.1",
"map-async": "~0.1.1",
"tuple-stream": "~0.0.2",
"split": "~0.2.10",
"through": "~2.3.4",
"mkdirp": "~0.3.5",
"colors-tmpl": "~0.1.0",
"terminal-menu": "~0.2.0",
"msee": "~0.1.1",
"optimist": "~0.6.0",
"xtend": "~2.1.1",
"msee": "~0.1.0-alpha.3"
"split": "~0.2.10",
"terminal-menu": "~0.2.0",
"through": "~2.3.4",
"tuple-stream": "~0.0.2",
"xtend": "~2.1.2",
"shelljs": "~0.5.3"
}
}
14 changes: 9 additions & 5 deletions print-text.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
const fs = require('fs')
, path = require('path')
, colorsTmpl = require('colors-tmpl')
, msee = require('msee')
const fs = require('fs')
, path = require('path')
, colorsTmpl = require('colors-tmpl')
, msee = require('msee')
, mseeOptions = {
paragraphStart: ''
, paragraphEnd: '\n\n'
}

function printText (name, appDir, file, filetype, callback) {
var variables = {
Expand All @@ -24,7 +28,7 @@ function printText (name, appDir, file, filetype, callback) {
})
if (filetype == '.md') {
// convert Markdown to ANSI
contents = msee.parse(contents)
contents = msee.parse(contents, mseeOptions)
}
console.log(contents)
callback && callback()
Expand Down
6 changes: 6 additions & 0 deletions strings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"guide": "» Open the guide in your browser: jlord.github.io/git-it\n » Traditional Chinese guide: jlord.github.io/git-it/index-zhtw.html",
"offline": "» To view guide offline, copy this address to your browser:\n » pathtoguide + .html \n » pathtoguide + -zhtw.html\n",
"verify": "» To verify your work for this problem, run: `git -it verify`.\n",
"next": "» Run `git-it` again to launch menu & go onto next challenge.\n'"
}
8 changes: 4 additions & 4 deletions usage.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
Show the currently selected workshop.
{bold}{green}{appname}{/green} print{/bold}
Print the instructions for the currently selected workshop.
{bold}{green}{appname}{/green} run program.js{/bold}
Run your program against the selected input.
{bold}{green}{appname}{/green} verify program.js{/bold}
Verify your program against the expected output.
{bold}{green}{appname}{/green} run{/bold}
Run the challenge's verify without triggering verify.
{bold}{green}{appname}{/green} reset{/bold}
Clear all challenges completed status.
127 changes: 87 additions & 40 deletions workshopper.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ const argv = require('optimist').argv
, mkdirp = require('mkdirp')
, map = require('map-async')
, msee = require('msee')
, http = require('http')
, ecstatic = require('ecstatic')
, _ = require('lodash')
, shell = require('shelljs')


const showMenu = require('./menu')
, verify = require('./verify')
Expand All @@ -15,9 +20,13 @@ const showMenu = require('./menu')
, yellow = require('./term-util').yellow
, center = require('./term-util').center

const defaultWidth = 65
var strings = require('./strings');

const defaultWidth = 65;

function Workshopper (options) {
strings = _.assign(strings, options.strings)

if (!(this instanceof Workshopper))
return new Workshopper(options)

Expand Down Expand Up @@ -59,9 +68,10 @@ Workshopper.prototype.init = function () {
if (argv.s || argv.server || argv._[0] == 'server')
if (argv._[1]) {
return this._runServer(argv._[1])
} else {
}
else {
return this._runServer()
}
}

if (argv._[0] == 'credits')
return this._printCredits()
Expand All @@ -83,15 +93,19 @@ Workshopper.prototype.init = function () {

if (argv._[0] == 'select' || argv._[0] == 'print') {
return onselect.call(this, argv._.length > 1
? argv._.slice(1).join(' ')
: this.getData('current')
? argv._.slice(1).join(' ')
: this.getData('current')
)
}

var run = argv._[0] == 'run'
if (argv._[0] == 'verify' || run)
return this.verify(run)

if (argv._[0] == 'reset') {
return this.reset()
}

this.printMenu()
}

Expand All @@ -109,6 +123,7 @@ Workshopper.prototype.verify = function (run) {
dir = this.dirFromName(current)
setupFn = require(dir + '/setup.js')


if (!setupFn.async) {
setup = setupFn(run)
return setTimeout(this.runSolution.bind(this, setup, dir, current, run), setup.wait || 1)
Expand Down Expand Up @@ -160,6 +175,11 @@ Workshopper.prototype.problems = function () {
return this._problems
}

Workshopper.prototype.reset = function () {
fs.unlink(path.resolve(this.dataDir, 'completed.json'), function () {})
fs.unlink(path.resolve(this.dataDir, 'current.json'), function () {})
}

Workshopper.prototype.getData = function (name) {
var file = path.resolve(this.dataDir, name + '.json')
try {
Expand Down Expand Up @@ -194,7 +214,7 @@ Workshopper.prototype.runSolution = function (setup, dir, current, run) {
bold(yellow((run ? 'Running' : 'Verifying') + ' "' + current + '"...')) + '\n'
)

var a = submissionCmd(setup)
var a = submissionCmd(dir, setup)
, b = solutionCmd(dir, setup)
, v = verify(a, b, {
a : setup.a
Expand Down Expand Up @@ -236,7 +256,9 @@ function solutionCmd (dir, setup) {
return exec.concat(args)
}

function submissionCmd (setup) {
function submissionCmd (dir, setup) {
var filename = argv._[1]
if (!filename) filename = dir + '/verify.js'
var args = setup.args || setup.submissionArgs || []
, exec

Expand All @@ -247,14 +269,14 @@ function submissionCmd (setup) {
, require.resolve('./module-use-tracker')
, setup.modUseTrack.trackFile
, setup.modUseTrack.modules.join(',')
, argv._[1]
, filename
]
} else if (setup.execWrap) {
exec = [ require.resolve('./exec-wrapper') ]
exec = exec.concat(setup.execWrap)
exec = exec.concat(argv._[1])
exec = exec.concat(filename)
} else {
exec = [ argv._[1] ]
exec = [ filename ]
}

return exec.concat(args)
Expand Down Expand Up @@ -297,13 +319,11 @@ Workshopper.prototype._printUsage = function () {

function onpass (setup, dir, current) {
console.log(bold(green('# PASS')))
console.log('\nYour solution to ' + current + ' passed!')
console.log(green(bold('\nYour solution to ' + current + ' passed!')))

if (setup.hideSolutions)
return

console.log('\nHere\'s what the official solution is if you want to compare notes:\n')

var solutions = fs.readdirSync(dir).filter(function (file) {
return (/^solution.*\.js/).test(file)
}).map(function (file) {
Expand All @@ -328,14 +348,14 @@ function onpass (setup, dir, current) {
if (err)
throw err

solutions.forEach(function (file, i) {
console.log(repeat('-', this.width) + '\n')
if (solutions.length > 1)
console.log(bold(file.name) + ':\n')
console.log(file.content)
if (i == solutions.length - 1)
console.log(repeat('-', this.width) + '\n')
}.bind(this))
// solutions.forEach(function (file, i) {
// console.log(repeat('-', this.width) + '\n')
// if (solutions.length > 1)
// console.log(bold(file.name) + ':\n')
// console.log(file.content)
// if (i == solutions.length - 1)
// console.log(repeat('-', this.width) + '\n')
// }.bind(this))

this.updateData('completed', function (xs) {
if (!xs) xs = []
Expand All @@ -347,8 +367,34 @@ function onpass (setup, dir, current) {

remaining = this.problems().length - completed.length
if (remaining === 0) {
console.log(repeat('-', this.width))
console.log('Here\'s what our solution looks like:' + '\n')

var example = fs.readdirSync(dir).filter(function (file) {
return (/^example.*\.html/).test(file)
}).map(function (file) {
shell.echo(fs.readFileSync(path.join(dir, file), 'utf8'))
// .toString()
// .replace(/^/gm, ' ')
}
)
console.log(repeat('-', this.width))
console.log('You\'ve finished all the challenges! Hooray!\n')
} else {
// trying to show our example
console.log(repeat('-', this.width))
console.log('Here\'s what our solution looks like:' + '\n')

var example = fs.readdirSync(dir).filter(function (file) {
return (/^example.*\.html/).test(file)
}).map(function (file) {
shell.echo(fs.readFileSync(path.join(dir, file), 'utf8'))
// .toString()
// .replace(/^/gm, ' ')
}
)

console.log(repeat('-', this.width) + '\n')
console.log(
'You have '
+ remaining
Expand All @@ -357,6 +403,7 @@ function onpass (setup, dir, current) {
+ ' left.'
)
console.log('Type `' + this.name + '` to show the menu.\n')
console.log(repeat('-', this.width) + '\n')
}

if (setup.close)
Expand All @@ -373,6 +420,20 @@ function onfail (setup, dir, current) {
console.log('\nYour solution to ' + current + ' didn\'t pass. Try again!')
else
console.log('\nYour solution to ' + current + ' didn\'t match the expected output.\nTry again!')
console.log(repeat('-', this.width) + '\n')

// trying to show our example
console.log('Here\'s what our solution looks like:')

var example = fs.readdirSync(dir).filter(function (file) {
return (/^example.*\.html/).test(file)
}).map(function (file) {
shell.echo(fs.readFileSync(path.join(dir, file), 'utf8'))
// .toString()
// .replace(/^/gm, ' ')
}
)
console.log(repeat('-', this.width) + '\n')
}

function onselect (name) {
Expand All @@ -396,26 +457,12 @@ function onselect (name) {
file = txt

printText(this.name, this.appDir, file, path.extname(file), function () {
console.log(
bold('\n » To print these instructions again, run: `' + this.name + ' print`.'))
console.log(
bold(' » To execute your program in a test environment, run:\n `' + this.name + ' run program.js`.'))
console.log(
bold(' » To verify your program, run: `' + this.name + ' verify program.js`.'))
if (this.helpFile) {
console.log(
bold(' » For help with this problem or with ' + this.name + ', run:\n `' + this.name + ' help`.'))
}
if (this.creditsFile) {
console.log(
bold(' » For a list of those who contributed to ' + this.name + ', run:\n `' + this.name + ' credits`.'))
}
if (this.prerequisitesFile) {
console.log(
bold(' » For any set up/installion prerequisites for ' + this.name + ', run:\n `' + this.name + ' prerequisites`.'))
}
console.log()
console.log(bold(green(strings.verify)))
console.log(bold(green(strings.next)))
console.log(bold(green(strings.guide)))
console.log(bold(green(strings.offline)))
}.bind(this))
}


module.exports = Workshopper