Table of Contents
Pipe
Make a pipable
Pipable is a object, which have a method named .pipe(fun,...args)
.
You can get a new pipable object as fellow ways:
const {
Pipe,
pipe,
from,
_
} = require('./pipe.js')
test('make pipable', () => {
const properties = ['valueOf', 'pipe', 'map', "promise_rescue"].sort();
const keys = Object.keys.bind(Object);
expect(keys(Pipe(1)).sort()).toMatchObject(properties);
expect(keys(pipe(1)).sort()).toMatchObject(properties);
expect(keys(from(1)).sort()).toMatchObject(properties);
expect(keys(from(1).pipe(a => a + 1)).sort()).toMatchObject(properties);
})
As then snippet showed, a pipable
object have methods as fellow:
-
pipable.valueOf()
:Get the
v
you want to pipe to other function.So
pipe(a).valueOf() === a
is alwaystrue
:test('pipe(any).valueOf() == any', () => { expect(pipe(1).valueOf() == 1).toBe(true) expect(pipe("hello").valueOf() == "hello").toBe(true); expect(pipe(true).valueOf() == true).toBe(true); expect(pipe(false).valueOf() == false).toBe(true); let str = new String('Hello'); expect(pipe(str).valueOf() == str).toBe(true); expect(pipe(null).valueOf() == null).toBe(true); expect(pipe(undefined).valueOf() == undefined).toBe(true); let a = { hello: "a" }; expect(pipe(a).valueOf() == a).toBe(true) })
If a
is primary type but neither null
nor undefined
then pipe(a) == a
is true.
test('pipe(primary) == primary', () => {
expect(pipe(1) == 1).toBe(true)
expect(pipe("hello") == "hello").toBe(true);
expect(pipe(true) == true).toBe(true);
expect(pipe(false) == false).toBe(true);
let str = new String('Hello')
expect(pipe(str) == str).toBe(false);
expect(pipe(null) == null).toBe(false);
expect(pipe(undefined) == undefined).toBe(false);
let a = { hello: "a" };
expect(pipe(a) == a).toBe(false);
})
-
pipable.pipe(fun,...args)
: Return a pipable object.fun
is a function,args
are the rest arguments you want pipe tofun
.-
If
args
do not included placeholder_
,fun
will be called asfun(...[v,...args])
. -
If
args
included one and only one placeholder_
,pipable.valueOf()
will instead of the placehoder, andfun
will be called asfun(...args)
.
-
-
pipable.map(fun,...args)
:pipable.map
is the alias ofpipable.pipe
. -
pipable.promise_rescue(fun,...args)
: return a new pipable object.- when the
pipable.vlaueOf()
is a promise and the promise is reject, the reject reason will pipe tofun
. - when
pipeable.valueOf()
is not a promise,fun
will been skiped and return copy ofpipable
.
- when the
fun
take the piped value
Use placeholder set which argument of test('pipe with placeholder', () => {
let fn = jest.fn((a, b, c) => a + b + c);
let z = pipe('a').pipe(fn, 'b', 'c');
expect(fn).not.toHaveBeenCalled();
expect(z == 'abc').toBe(true);
expect(fn).toBeCalledWith('a', 'b', 'c');
z = pipe("2").pipe(fn, "1", _, "3");
expect(z == '123').toBe(true);
expect(fn).toBeCalledWith('1', '2', '3');
z = pipe('e').pipe(fn, 'a', 'b', 'c', 'd', _);
expect(z == 'abc');
expect(fn).toHaveBeenLastCalledWith('a', 'b', 'c', 'd', 'e');
})
pipable.pipe(fun,...args)
keep pipable
object immutable.
pipable.pipe(fn,...args)
will return a new pipable object,don't change the old one.
test('pipable is independ', () => {
let a = 1;
let fn1 = jest.fn(a => a + 1);
let fn2 = jest.fn((b, c) => b + c);
let pipable0 = pipe(a);
let pipable1 = pipable0.pipe(fn1);
expect(pipable1 == a + 1).toBe(true);
expect(pipable0.valueOf()).toBe(a);
let pipable2 = pipable1.pipe(fn2, 'c');
expect(pipable2 == '2c').toBe(true);
expect(pipable1.valueOf()).toBe(a + 1);
})
pipable.pipe(fn,...args)
is lazy
Call pipeable.pipe(fn,...args)
do not call fn
,
but pipable.valueOf()
will call the fn
if there have one.
As fellow show:
test(`pipable is layze`, () => {
const fn = jest.fn(a => a + 1);
let pipable0 = pipe(1);
let ret = pipable0.pipe(fn).pipe(fn).pipe(fn);
expect(fn).not.toHaveBeenCalled();
expect(ret.valueOf()).toBe(1 + 1 + 1 + 1);
expect(fn.mock.calls).toMatchObject([[1], [2], [3]]);
})
pipable<Promise>.pipe(fn,...args)
If the value of a pipable is a Promise
,
pipable.pipe(fn)
pipe the resolve value of the promise to fn
,
and return a new promise pipable.
Examaples
test('pipe promise resolve ', (done) => {
let a = from(Promise.resolve(1));
expect(a.valueOf()).toBeInstanceOf(Promise);
let fn = jest.fn(a => a + 1);
let ret = a.pipe(fn).
promise_rescue(fn).//skip
pipe(fn).valueOf();
expect(ret).toBeInstanceOf(Promise);
ret.then(() => {
expect(fn.mock.calls).toMatchObject([[1], [2]]);
done();
});
})
pipable<Promise>.promise_rescue
:
Return a new pipable.
If value of pipable<Promise>
is reject, this method can rescue from the error.
test('pipe promise reject', (done) => {
let a = from(Promise.reject('hello'));
let fn1 = jest.fn(a => 'fn1');
let fn2 = jest.fn(a => 'fn2');
let fn3 = jest.fn(a => "fn3");
let promise = a.pipe(fn1).//skip
promise_rescue(fn2).//call
pipe(fn3).valueOf();
expect(promise).toBeInstanceOf(Promise);
promise.then(
(a) => {
expect(fn1).not.toHaveBeenCalled();
expect(fn2).toHaveBeenCalledWith('hello');
expect(fn3).toHaveBeenCalledWith('fn2');
expect(a).toBe('fn3');
done();
},
(error) => {
console.error(error);
expect('not run to here').toBe('but it is here');
}
)
})
pipable.inspect(fn, ...args)
Return a new pipable
.
Run then function fn
, ignor the return value of fn
, so the value of the pipable will keep not change.
The purpose of this method is helpfully debuging the pipeable chain.