From 0a0316a0002cef97043d8e9388bc55c2e8e41074 Mon Sep 17 00:00:00 2001 From: d98762625 Date: Fri, 11 May 2018 19:25:14 +0100 Subject: [PATCH] Make optional args in operation call use named properties rather than array --- src/node/apiUtils.mjs | 47 ++++++++++++++++++++++++------ test/tests/nodeApi/nodeApi.mjs | 22 ++++++++++++++ test/tests/nodeApi/translateTo.mjs | 7 +++-- 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/node/apiUtils.mjs b/src/node/apiUtils.mjs index 4efcdc84..a076ce95 100644 --- a/src/node/apiUtils.mjs +++ b/src/node/apiUtils.mjs @@ -20,10 +20,41 @@ function extractArg(arg) { return arg.value; } +/** + * transformArgs + * + * Take the default args array and update with any user-defined + * operation arguments. Allows user to define argyments in object style, + * with accommodation name matching. Using named args in the API is more + * clear to the user. + * + * Argument name matching is case and space insensitive + * @private + * @param {Object[]} originalArgs + * @param {Object} newArgs + */ +function transformArgs(originalArgs, newArgs) { + const allArgs = Object.assign([], originalArgs); + + if (newArgs) { + Object.keys(newArgs).map((key) => { + const index = allArgs.findIndex((arg) => { + return arg.name.toLowerCase().replace(/ /g, "") === + key.toLowerCase().replace(/ /g, ""); + }); + if (index > -1) { + allArgs[index].value = newArgs[key]; + } + }); + } + return allArgs.map(extractArg); +} + /** * Wrap an operation to be consumed by node API. * new Operation().run() becomes operation() * Perform type conversion on input + * @private * @param {Operation} Operation * @returns {Function} The operation's run function, wrapped in * some type conversion logic @@ -49,14 +80,7 @@ export function wrap(Operation) { const type = Dish.typeEnum(input.constructor.name); dish.set(input, type); - if (!args) { - args = operation.args.map(extractArg); - } else { - // Allows single arg ops to have arg defined not in array - if (!(args instanceof Array)) { - args = [args]; - } - } + args = transformArgs(operation.args, args); const transformedInput = await dish.get(operation.inputType); // Allow callback or promsise / async-await @@ -104,7 +128,12 @@ function extractOperationInfo(Operation) { description: operation.description, inputType: operation.inputType, outputType: operation.outputType, - args: Object.assign([], operation.args), + // Make arg names lowercase, no spaces to encourage non-sentence + // caps in repl + args: Object.assign([], operation.args).map((s) => { + s.name = decapitalise(s.name).replace(/ /g, ""); + return s; + }) }; } diff --git a/test/tests/nodeApi/nodeApi.mjs b/test/tests/nodeApi/nodeApi.mjs index c6215a63..baf29502 100644 --- a/test/tests/nodeApi/nodeApi.mjs +++ b/test/tests/nodeApi/nodeApi.mjs @@ -59,5 +59,27 @@ TestRegister.addApiTests([ } assert(false); }); + }), + + it("should accept arguments in object format for operations", async () => { + const result = await chef.setUnion("1 2 3 4:3 4 5 6", { + itemDelimiter: " ", + sampleDelimiter: ":" + }); + + assert.equal(result, "1 2 3 4 5 6"); + }), + + it("should accept just some of the optional arguments being overriden", async () => { + const result = await chef.setIntersection("1 2 3 4 5\\n\\n3 4 5", { + itemDelimiter: " ", + }); + + assert.equal(result, "3 4 5"); + }), + + it("should accept no override arguments and just use the default values", async () => { + const result = await chef.powerSet("1,2,3"); + assert.equal(result, "\n3\n2\n1\n2,3\n1,3\n1,2\n1,2,3\n"); }) ]); diff --git a/test/tests/nodeApi/translateTo.mjs b/test/tests/nodeApi/translateTo.mjs index fa3f74aa..528e35d5 100644 --- a/test/tests/nodeApi/translateTo.mjs +++ b/test/tests/nodeApi/translateTo.mjs @@ -3,7 +3,7 @@ /** * nodeApi.js * - * Test node api utilities + * Test node api translateTo function * * @author d98762625 [d98762625@gmail.com] * @copyright Crown Copyright 2018 @@ -39,7 +39,10 @@ TestRegister.addApiTests([ }), it("should be symmetric", async () => { - const result = await chef.setUnion("1 2 3 4:3 4 5 6", [":", " "]); + const result = await chef.setUnion("1 2 3 4:3 4 5 6", { + itemDelimiter: " ", + sampleDelimiter: ":" + }); const bytearray = await chef.translateTo(result, "bytearray"); const translated = await chef.translateTo(bytearray, "string"); assert.equal(translated, "1 2 3 4 5 6");