Simple example of how to read a list from a KM Variable, or a file, and then select the desired item by position in the list.
Created in response to this question:
###Script
main()
function main() {
var app = Application.currentApplication()
app.includeStandardAdditions = true
var kmeApp = Application("Keyboard Maestro Engine");
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// #### CHOOSE THE METHOD FOR SOURCE ####
// Comment out or Delele the unused method
//#1 -- KM VARIABLE
var zipData = kmeApp.getvariable("zipData");
// OR
//#2 -- FILE
/*
var pathInputFile = app.chooseFile({
prompt: "Select the ZipCode file",
type: "text"
})
//--- READ THE FILE CONTENTS ---
var zipData = app.read(pathInputFile)
*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//----- NOW, CONVERT ZIP DATA TO ZIP LIST ---
var zipList = zipData.split("\n");
var zipCodePos = kmeApp.getvariable("zipCodePos"); // must SET this KM Var PRIOR to Executing Script
var zipCode = zipList[zipCodePos-1];
kmeApp.setvariable('zipCode', { to: zipCode });
// OR
// just return the zipCode to a Execute Script Action with Variable
return zipCode
} // END function main
//--=============== END OF MAIN SCRIPT ==============
Doesn’t make much difference here (except perhaps to readability ?) but it’s generally worth caching methods of an object if they are going to be used repeatedly.
It’s not that I doubt you… no wait, I do doubt you. Can you show me a legitimate example where this would make a noticeable difference, with scripts used with KM?
I do agree with you to the extent that I think run-time performance is generally a frivolous preoccupation for personal desktop scripting, and not something that I would chase except on a very wet weekend.
On the other hand, that’s an argument for not caching the reference to the application object either – something which we all seem to do as a kind of reflex, and because the cognitive processing costs are lower, both in the reading and the writing.
Here, if you’re going to cache at all, I would personally prefer to cache the reference to the method, rather than just the reference to the application object.
I wouldn’t be particularly interested in changing anyone else’s view, but for me this is a bit cleaner and more readable, and for some reason (don’t tell Peter) I don’t entirely like the all-lower-case .getvariable method name
(Also, I notice that scripters don’t always seem be very keenly aware of functions as first-class objects in themselves – they may not think of binding a local name to a function/method in the way that they would automatically do with a number or string, for example.)
I have not done any timing studies, but I can say that when I have used the below function I have not noticed any material delays. The response is near instantaneous (from the end user’s perspective).
While you might be able to shave some milliseconds off execution time, IMO it is not worth the extra programming effort (and the potential introduction of bugs) to use “caching methods of an object”.
I suppose if I were designing a system where this function is a low level function where the call to the object method could be done hundreds or thousands of times, then it might be worth optimizing the code. But that is rarely the case with the scripts used in KM macros.
This function loops through many KM variables as defined in the pObject parameter, which came from a JSON.
function setKMVarsFromObject(pObject, pVarPrefix) {
var kme = Application("Keyboard Maestro Engine");
var prefix = pVarPrefix || "";
var numKMVars = 0
var KMVars = "";
Object.keys(pObject).forEach(function(key) {
//console.log(prefix + key + ': ' + pObject[key]);
numKMVars += 1;
KMVars += "\n" + prefix + key;
kme.setvariable(prefix + key, { to: pObject[key] });
});
return "Num of KM Variables Set: " + numKMVars + KMVars;
If I remember correctly, this function is based on large part on a script written by @DanThomas. Thanks, Dan. Your script has been very useful.
IIRC, I did write something like that, but of course you’ve changed the variable names (which I would do if the roles were reversed, so no worries there).
The code I personally use most of the time actually does wrap the “setvariable” function, although it doesn’t cache it (but it could). I probably decided that for what we were talking about, it was better to provide less code than more.
There again, mileage will vary, and the stakes are low to negligible, but instead of caching the reference to the application object, as you are already doing (not strictly necessary either, and you might be hard pressed, there too, to notice the performance benefit), you might as well cache where it counts, save a little typing, and remove a little noise.
var setVar = Application('Keyboard Maestro Engine').setvariable;
...
setVar(prefix + key, { to: pObject[key] });
Perhaps. But “efficient code” can often come at the expense of readability and maintainability.
“Efficient code” can often be difficult to read/understand by others, and even by the original author months later. I first encountered this decades ago, when the “expert” programmers wanted to use assembly language for small performance gains.
Reducing readability and maintainability for the benefit of a small performance gain does not seem wise to me.
But each of us is clearly free to choose the style each prefers.
Since this is my topic, specifically about posting a macro, may I ask you guys who wish to further discuss optimizing code to start a new thread. Thanks.