# Instructions

[![Build Status](https://travis-ci.org/xeno-dohai/instructions.svg?branch=master)](https://travis-ci.org/xeno-dohai/instructions)

Chain of instructions to process your input.

## Installing

Using yarn:

```
yarn add instructions
```

Using npm:

```
npm install --save instructions
```

## Start chain of Instructions

Start a chain of instructions using `startWith` function.

`startWith` will return an instance of `Instruction`.

**Arguments**

- _value: any_: Input to be processed with chain of instructions.

**Returns**

- _(Instruction)_: Return a new `Instruction` wrapper instance.

**Example**

Create an inital instruction with `startWith`.

```javascript
const { startWith } = require('instructions');

const initialInstructions = startWith({});
```

Chaining up instructions.

```javascript
const { startWith } = require('instructions');

const instructions = startWith({})
  .then(doSomething)
  .ifElse(predicate, truthyHalder, falsyHandler)
  .then(doAnotherThing);
```

## Instruction methods

**Notes**

- All `Instruction` methods except `toPromise()` will return an instance of `Instruction` allowing you to chain your instructions.
- All handlers should return a value which will be passed to as first argument of next handler in the chain of instructions.
- Handlers can be sync or async function.

### .toPromise(formatter)

Returns result of instructions chain as `Promise`.

**Arguments**

- **(Optional)** _formatter: (any): any_: Handler to format the result before being returned as `Promise`.

**Example**

```javascript
const result = startWith({ message: 'Hello World' }).toPromise();

console.log(result); // => Promise< pending >

result.then((value) => console.log(value.message)); // => 'Hello World'
```

### .then(handler)

Like `Promise.then()`, handler receives value from previous handler as argument and returns a value which will be passed on to next Instruction in chain.

**Arguments**

- _handler: (any): any_: Function that receive result of previous Instruction and returns input for next Instruction.

**Example**

```javascript
await startWith({})
  .then((value) => {
    value.message = 'Hello World';
    return value;
  })
  .toPromise(); // { message: 'Hello World' }
```

### .ifElse(condition, truthyHandler, falsyHandler)

Instruction that will process either `truthyHanlder` or `falsyHandler` depending on result of `condition` predicate.

**Arguments**

- _condition(any): boolean_: Function which will receive result of previous Instruction as argument. Result which returned from this function will determine either `truthyHandler` or `falsyHandler` will be processed.
- _trutyHandler(any): any_: Standard Instruction handler which will be processed if `condition` predicate returns truthy value.
- _falsyHandler(any): any_: Standard Instruction handler which will be processed if `condition` predicate returns falsy value.

**Example**

```javascript
await startWith({})
  .ifElse(
    () => true,
    () => ({ message: 'Predicate returns true!' }),
    () => ({ message: 'Predicate returns false!' }),
  ).toPromise(); // => { message: 'Predicate returns true!' }
```

### .failOver(handler, failOverHandler)

Instruction which will process `failOverHandler` if `handler` throw an exception.

**Arguments**

- _handler(any): any_: Standard Instruction handler.
- _failOverHandler(any, Error): any_ Standard Instruction handler which will be processed if `handler` throw an exception. Exception will be passed as second argument.

**Example**

```javascript
await startWith({})
  .failOver(
    () => throw Error('Boom!'),
    (_, err) => ({ message: err.message + ' is catched' }),
  ).toPromise(); // => { message: 'Boom! is catched' }
```

### .concurrent(handlers)

Instruction which receives an array of handlers then executes them concurrently. Result of all handlers will be merged then passed to next Instruction.

**Arguments**

- _handlers: ((any): any)[]_: An array of handlers which will be executed concurrently.

**Example**

```javascript
await startWith({})
  .concurrent([
    () => ({ message1: 'Hi Mom!'}),
    () => ({ message2: 'Hi Dad!'}),
  ]).toPromise(); // => { message1: 'Hi Mom!', message2: 'Hi Dad!' }
```

### .inCaseOf(condition, cases)

Instruction which will process handler of case that match with the result of `condition` predicate.

**Arguments**

- _condition(any): any_: Function that receive result of last Instruction as argument and which result will be evaluated to decide which case will be processed.
- _cases: [any, (any) => any]   []_: An array of tuple.
  - First element of tuple will be tested with result of `condition` predicate.
  - Second element is standard handler.
  - **Note**: a wildcard(`*`) case is required. This case will be processed if no other case is matched. The result of `condition` predicate will be passed as second argument of wildcard case handler.

**Example**

```javascript
await startWith({})
  .inCaseOf(
    () => 5,
    [
      [1, () => ({ message: 'The result is 1' })],
      [2, () => ({ message: 'The result is 2' })],
      ['*', (_, predicateResult) => ({ message: 'The result is ' + predicateResult })],
    ]
  ).toPromise(); // => { message: 'The result is 5' }
```

## Changelog
Please refer to [CHANGELOG.md](./CHANGELOG.md)
