Skip to content

Commit

Permalink
assign optional values/Promises in addition to resolvers
Browse files Browse the repository at this point in the history
  • Loading branch information
richytong committed Dec 15, 2024
1 parent 2ac95c9 commit d8e3877
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 29 deletions.
3 changes: 2 additions & 1 deletion _internal/functionObjectAll.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const objectSet = require('./objectSet')
const functionObjectAll = function (funcs, args) {
const result = {}, promises = []
for (const key in funcs) {
const resultItem = funcs[key](...args)
const f = funcs[key]
const resultItem = typeof f == 'function' ? f(...args) : f
if (isPromise(resultItem)) {
promises.push(resultItem.then(curry3(objectSet, result, key, __)))
} else {
Expand Down
22 changes: 19 additions & 3 deletions assign.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@ const _assign = function (object, funcs) {
*
* @synopsis
* ```coffeescript [specscript]
* assign(object Promise|Object, resolvers Object<function>) -> result Promise|Object
* assign(
* o Promise|Object,
* resolversOrValues Object<function|Promise|any>
* ) -> result Promise|Object
*
* assign(resolvers Object<function>)(object Object) -> result Promise|Object
* assign(
* resolversOrValues Object<function|Promise|any>
* )(o Object) -> result Promise|Object
* ```
*
* @description
* Function executor and composer. Accepts an object of resolver functions and an argument object. Creates a result object from the argument object, evaluates each resolver with the argument object, and assigns to the result object the evaluations at the corresponding resolver keys.
* Function executor and composer. Accepts an object of resolver functions or values and an object `o`. Creates a result object from the argument object, evaluates each resolver with the argument object, and assigns to the result object the evaluations at the corresponding resolver keys.
*
* ```javascript [playground]
* const assignSquaredAndCubed = assign({
Expand Down Expand Up @@ -55,6 +60,17 @@ const _assign = function (object, funcs) {
* // { numbers: [1, 2, 3, 4, 5], total: 15 }
* ```
*
* Values passed in resolver position are set on the result object directly. If any of these values are promises, they are resolved for their values before being assigned to the result object.
*
* ```javascript [playground]
* assign({}, {
* a: 1,
* b: Promise.resolve(2),
* c: () => 3,
* d: async o => Object.keys(o).length,
* }).then(console.log) // { a: 1, b: 2, c: 3, d: 0 }
* ```
*
* Any promises passed in argument position are resolved for their values before further execution. This only applies to the eager version of the API.
*
* ```javascript [playground]
Expand Down
40 changes: 15 additions & 25 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,33 +488,33 @@ describe('rubico', () => {
)
})
it('maps input to array of sync functions', async () => {
ade(all([hi, hi, hi])('yo'), ['yohi', 'yohi', 'yohi'])
ade(all([hi, hi, hi])('hi'), ['hihi', 'hihi', 'hihi'])
})
it('maps input to object of sync functions', async () => {
ade(
all({ a: hi, b: hi, c: hi })('yo'),
{ a: 'yohi', b: 'yohi', c: 'yohi' },
all({ a: hi, b: hi, c: hi })('hi'),
{ a: 'hihi', b: 'hihi', c: 'hihi' },
)
})
it('maps input to array of async functions', async () => {
aok(all([asyncHey, asyncHey, asyncHey])('yo') instanceof Promise)
aok(all([asyncHey, asyncHey, asyncHey])('hi') instanceof Promise)
ade(
await all([asyncHey, asyncHey, asyncHey])('yo'),
['yohey', 'yohey', 'yohey'],
await all([asyncHey, asyncHey, asyncHey])('hey'),
['heyhey', 'heyhey', 'heyhey'],
)
})
it('maps input to object of async functions', async () => {
aok(all({ a: asyncHey, b: asyncHey, c: asyncHey })('yo') instanceof Promise)
ade(
await all({ a: asyncHey, b: asyncHey, c: asyncHey })('yo'),
{ a: 'yohey', b: 'yohey', c: 'yohey' },
await all({ a: asyncHey, b: asyncHey, c: asyncHey })('hey'),
{ a: 'heyhey', b: 'heyhey', c: 'heyhey' },
)
})
it('any functions async => Promise', async () => {
aok(all([asyncHey, asyncHey, hi])('yo') instanceof Promise)
aok(all([asyncHey, asyncHey, hi])('1') instanceof Promise)
ade(
await all([asyncHey, asyncHey, hi])('yo'),
['yohey', 'yohey', 'yohi'],
await all([asyncHey, asyncHey, hi])('1'),
['1hey', '1hey', '1hi'],
)
})
it('all([])() -> []', async () => {
Expand All @@ -531,18 +531,6 @@ describe('rubico', () => {
new TypeError('funcs[funcsIndex] is not a function'),
)
})
it('throws TypeError for all({ a: nonFunction })', async () => {
assert.throws(
() => all({ a: 'hey' })(),
new TypeError('funcs[key] is not a function'),
)
})
it('throws TypeError for String', async () => {
assert.throws(
() => all('ayelmao')(),
new TypeError('funcs[key] is not a function'),
)
})
it('{} for Set<[func]>; no functions exposed via in', async () => {
assert.deepEqual(all(new Set([() => 'yo']))('hey'), {})
})
Expand Down Expand Up @@ -638,11 +626,13 @@ describe('rubico', () => {

describe('assign', () => {
it('API coverage', async () => {
ade(assign({}, {
ade(await assign({}, {
a: () => 1,
b: () => 2,
c: () => 3,
}), { a: 1, b: 2, c: 3 })
e: 4,
f: Promise.resolve(5),
}), { a: 1, b: 2, c: 3, e: 4, f: 5 })

ade(assign({
a: () => 1,
Expand Down

0 comments on commit d8e3877

Please sign in to comment.