Expr

expr() allows you turn a function into an agent:
  /*!*/import { wrap, map, expr, group } from '@connectv/core';
import { fromEvent } from 'rxjs';

let a = document.getElementById('a') as HTMLInputElement;
let b = document.getElementById('b') as HTMLInputElement;
let p = document.getElementById('p');

group(
  wrap(fromEvent(a, 'input')).to(map(() => parseInt(a.value))),  //--> get the value of 'a'
  wrap(fromEvent(b, 'input')).to(map(() => parseInt(b.value))),  //--> get the value of 'b'
)
/*!*/.serialTo(expr((a, b) => a + b))                                 //--> add them
.subscribe(v => p.innerHTML = v);                                //--> display the result
expr()s support implicit connection, as evident from the example above. In this example, if you wanted to do the same thing explicitly, it would look like this:
let e = expr((a, b) => a + b);

group(...).serialTo(e.in(0), e.in(1));
e.result.subscribe(...); //--> `e.result` is short-hand for `e.out('result')`

Async functions

You can run async operations in an expr() by returning a function as return value:
  /*!*/import { source, sink, expr, group } from '@connectv/core';

let a = source();
let b = source();

group(a, b)
/*!*/.serialTo(expr((msg, delay) => 
/*!*/  done => {
/*!*/    setTimeout(() => done(`(after ${delay}ms): ${msg}`), delay);
/*!*/  })
)
.subscribe(console.log);

a.send('hellow'); b.send(100); //> `(after 100ms): hellow`
a.send('world');               //> `(after 100ms): world`
b.send(1000);                  //> `(after 1000ms): world`

Control

You can control when the function is executed using its .control property:
import { wrap, map, expr, group } from '@connectv/core';
import { fromEvent } from 'rxjs';

let a = document.getElementById('a') as HTMLInputElement;
let b = document.getElementById('b') as HTMLInputElement;
let btn = document.getElementById('btn');
let p = document.getElementById('p');

let e = expr((a, b) => a + b);

/*!*/wrap(fromEvent(btn, 'click'))         //--> wait for the click before
/*!*/  .to(e.control);                     //... running the function

group(
  wrap(fromEvent(a, 'input')).to(map(() => parseInt(a.value))),
  wrap(fromEvent(b, 'input')).to(map(() => parseInt(b.value))),
).serialTo(e)
.subscribe(v => p.innerHTML = v);
Note that the expr() waits for its control signal for every execution.

Error handling

Similar to map(), synchronous errors happening during execution of the function are handled automatically. For async errors, the returned function is similarly provided with an error callback as its second argument. You should catch possible errors and pass them to this callback:
  import { expr } from '@connectv/core';

//--> sync error handling in expr:

let e = expr(() => {
/*!*/  throw new Error('because why not');
});

e.result.subscribe(
  () => console.log('not here ...'),        //--> normal callback
/*!*/  () => console.log('E HAD ERROR!')         //--> error callback
);

//--> async error handling in expr:

/*!*/let brokenPromise = () => new Promise(() => { throw new Error('well ...')});

/*!*/let f = expr(() => (done, error) => {
  setImmediate(() =>
/*!*/    brokenPromise().catch(error));         //--> passing the caught error on ...
});

f.result.subscribe(
  () => console.log('not here too ...'),   //--> normal callback
/*!*/  () => console.log('F HAD ERROR!')        //--> error callback
)

Signature

An expr() will have one input pin for each input of your function, named numerically:
  let e = expr((a, b, c) => {
  // ...
});

e.in(0); //--> this pin's data goes to param a
e.in(1); //--> this pin's data goes to param b
e.in(2); //--> this pin's data goes to param c
Each expr() also has a "result" output, which will relay the return value of the function:
  e.out('result') //--> this will get you the return value
e.result        //--> this is a shortcut for the same thing

Further reading




Copied to Clipboard!