# workshopper-exercise

> An exercise runner component for the Workshopper framework

Latest version **3.0.3** (published 2020-06-04) · MIT license · 0 weekly downloads

## Install

```sh
npm install workshopper-exercise
pnpm add workshopper-exercise
yarn add workshopper-exercise
bun add workshopper-exercise
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 3.0.3 |
| Published | 2020-06-04 |
| First published | 2014-01-31 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 8 |
| Unpacked size | 36.2 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 57 |
| Author | Rod Vagg |
| Maintainers | julianduque, leichtgewicht, rvagg, tdd |

## Links

- npm: https://www.npmjs.com/package/workshopper-exercise
- Repository: https://github.com/rvagg/workshopper-exercise
- Homepage: https://github.com/rvagg/workshopper-exercise#readme
- Issues: https://github.com/rvagg/workshopper-exercise/issues
- npm.io page: https://npm.io/package/workshopper-exercise

## Dependencies (8)

- [after](https://npm.io/package/after.md) ~0.8.1
- [chalk](https://npm.io/package/chalk.md) ^1.1.1
- [split](https://npm.io/package/split.md) ^1.0.0
- [xtend](https://npm.io/package/xtend.md) ^4.0.1
- [through2](https://npm.io/package/through2.md) ^2.0.0
- [wcstring](https://npm.io/package/wcstring.md) ^2.1.0
- [i18n-core](https://npm.io/package/i18n-core.md) ^3.0.0
- [tuple-stream](https://npm.io/package/tuple-stream.md) 0.0.2

## Recent versions

- 3.0.3 (latest) — 2020-06-04
- 3.0.2 — 2020-06-04
- 3.0.1 — 2017-02-19
- 3.0.0 — 2017-02-19
- 2.7.0 — 2016-05-12
- 2.6.2 — 2016-05-05
- 2.6.1 — 2016-01-31
- 2.6.0 — 2016-01-31
- 2.5.3 — 2015-10-21
- 2.5.2 — 2015-10-21
- 2.5.1 — 2015-10-21
- 2.5.0 — 2015-10-20
- 2.4.0 — 2015-06-03
- 2.3.0 — 2015-02-16
- 2.2.0 — 2015-02-14
- … 16 more at https://npm.io/package/workshopper-exercise/versions

## README

[![NPM](https://nodei.co/npm/workshopper-exercise.png?foo)](https://nodei.co/npm/workshopper-exercise/)

## How to fail an exercise

In `/exercises/${EXERCISE_NAME}/exercise.js`:

```javascript
const exercise = require('workshopper-exercise')();

function sureToFail(errback) {
    exercise.emit('fail', 'told you it was going to fail');
    errback(null, false);
}

exercise.addVerifyProcessor(sureToFail);

module.exports = exercise;
```

This exercise will always fail, with the output:

```bash
 ✗ 

 told you it was going to fail

 # FAIL Your solution to ${EXERCISE_NAME} didn't pass. Try again!

─────────────────────────────────────────────────────────────────────────────

  » To print these instructions again, run: ${WORKSHOP_NAME} print
  » To execute your program in a test environment, run: ${WORKSHOP_NAME} run
    program.js
  » To verify your program, run: ${WORKSHOP_NAME} verify program.js
  » For help run: ${WORKSHOP_NAME} help 
```

## How use i18n-ed messages in an exercise

The term "i18n" is short for "internationalisation".
A workshopper exercise can surface messages in multiple languages
through its built-in i18n functionality:

1. Use `exercise.__(...)` in place of hard-coded strings, and
2. add the values to the relevant i18n file,
   as per workshopper's folder structure conventions.

In `/exercises/${EXERCISE_NAME}/exercise.js`:

```javascript
const exercise = require('workshopper-exercise')();

function pureLuck(errback) {
    const chance = Math.random();
    const pass = chance < 0.5;
    if (pass) {
        exercise.emit('pass', exercise.__('pass.lucky', { chance }));
    } else {
        exercise.emit('fail', exercise.__('fail.unlucky', { chance }));
    }
    errback(null, pass);
}

exercise.addVerifyProcessor(pureLuck);

module.exports = exercise;
```

`exercise.__(...)`:

- The 1st parameter is a `.` delimited key used for lookups in i18n files.
- The 2nd (optional) parameter is a hash of substitutions,
  and should be used for messages whose content is dynamic.

In `/i18n/${LANGUAGE_CODE}.json`:

```json
{
  ...
  "exercises": {
    "${EXERCISE_NAME}": {
      "pass": {
        "lucky": "You were lucky :) {{chance}}"
    },
      "fail": {
        "unlucky": "You were unlucky :( {{chance}}"
      }
    }
  }
}
```

Workshopper's i18n looks in several different places for the string values,
as i18n is used in many other parts of workshopper.
For exercises, the logical place to put them is in `exercises -> ${EXERCISE_NAME} -> ...`.
The `pass` and `fail` sub-objects are merely convention, 
and you do not have to use them -
any nesting below this is completely free-form.
The `{{...}}` are markers for templating,
using key-value pairs from the 2nd parameter to `exercise.__(...)`.

In order for your exercise to display multiple languages,
you will need to create one of these files per language,
where the keys are identical and the values are translated into each language.
For example, the line for `pass.lucky` for the தமிழ் language would be: 
`"lucky": "நீ அதிர்ஷ்டசாலி :) {{chance}}"`,
and would be in the `/i18n/ta.json` file.

When this exercise fails, it will output:

```bash
 ✗ 

 You were unlucky :( 0.5738622391092318

 # FAIL Your solution to ${EXERCISE_NAME} didn't pass. Try again!

─────────────────────────────────────────────────────────────────────────────

  » To print these instructions again, run: ${WORKSHOP_NAME} print
  » To execute your program in a test environment, run: ${WORKSHOP_NAME} run                                                                          
    program.js                                                                
  » To verify your program, run: ${WORKSHOP_NAME} verify program.js            
  » For help run: ${WORKSHOP_NAME} help
```

... and when it passes, it will output:

```bash
 ✓ 

 You were lucky :) 0.2753477873643899

 # PASS Your solution to ${EXERCISE_NAME} passed!

 You have ${REMAINING_EXERCISE_COUNT} challenges left.

 Type '${WORKSHOP_NAME}' to show the menu.

─────────────────────────────────────────────────────────────────────────────

  » To print these instructions again, run: ${WORKSHOP_NAME} print             
  » To execute your program in a test environment, run: ${WORKSHOP_NAME} run
    program.js
  » To verify your program, run: ${WORKSHOP_NAME} verify program.js
  » For help run: ${WORKSHOP_NAME} help
```

## How to get command line arguments

The command line arguments passed into the `verify` subcommand
can be accessed within an exercise via the `args` property.

In `/exercises/${EXERCISE_NAME}/exercise.js`:

```javascript
const exercise = require('workshopper-exercise')();

function firstArgMustBeFoo(errback) {
    const pass = exercise.args[0] === 'foo';
    if (pass) {
      exercise.emit('pass', 'first CLI argument was foo');
    } else {
      exercise.emit('fail', 'first CLI argument wasn\'t foo');
    }
    errback(null, pass);
}

exercise.addVerifyProcessor(firstArgMustBeFoo);

module.exports = exercise;
```

Command line arguments have a variety of use cases,
and in workshopper exercises,
one would typically use it to specify the submission file name.

When you run `${WORKSHOP_NAME} verify bar`, it will output:

```bash
 ✗ 

 first CLI argument wasn't foo

 # FAIL Your solution to ${EXERCISE_NAME} didn't pass. Try again!

─────────────────────────────────────────────────────────────────────────────

  » To print these instructions again, run: ${WORKSHOP_NAME} print
  » To execute your program in a test environment, run: ${WORKSHOP_NAME} run
    program.js
  » To verify your program, run: ${WORKSHOP_NAME} verify program.js
  » For help run: ${WORKSHOP_NAME} help
```

... and when you run `${WORKSHOP_NAME} verify foo`, it will output:

```bash
 ✓ 

 first CLI argument was foo

 # PASS Your solution to ${EXERCISE_NAME} passed!

 You have ${REMAINING_EXERCISE_COUNT} challenges left.

 Type '${WORKSHOP_NAME}' to show the menu.

─────────────────────────────────────────────────────────────────────────────

  » To print these instructions again, run: ${WORKSHOP_NAME} print
  » To execute your program in a test environment, run: ${WORKSHOP_NAME} run
    program.js
  » To verify your program, run: ${WORKSHOP_NAME} verify program.js
  » For help run: ${WORKSHOP_NAME} help
```

---
_Source: https://npm.io/package/workshopper-exercise · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
