Robotic Process Automation RPA

 View Only

How to extend IBM RPA with well-designed libraries

By Joba Diniz posted Thu April 07, 2022 03:15 PM

  
Say you want to create a library of utility functions to reuse throughout your RPA project. Say that library should contain the following functions
  • Get the current processing running
  • Expand environment variables
  • Get the file name given a file path
  • Get the file name without extension given a file path
Now you have a decision to make. Should you create 1 WAL script for each function? Well, you do not have to.
You can create 1 WAL script that receives which function to run as a parameter. It's like calling "executeScript.MyFunction", but in a way IBM RPA supports it.

Utils.wal
defVar --name methodName --type String --parameter
goSub --label "${methodName}"​

The above script receives a methodName parameter and calls the routine with that name.
Let's define the ExpandEnvironmentVariables routine, the input and output parameter environmentVariable.

Utils.wal

defVar --name methodName --type String --parameter
defVar --name environmentVariable --type String --parameter  --output
goSub --label "${methodName}"
beginSub --name ExpandEnvironmentVariables
endSub

Now my other WAL script can call the Utils.ExpandEnvironmentVariables like so:

Consumer.wal

defVar --name environmentVariable --type String
executeScript --name Utils --parameters "methodName=ExpandEnvironmentVariables,environmentVariable=%USERPROFILE%\\file.txt" --output "environmentVariable=${environmentVariable}"


What if my library has several functions and I want to call 2 or 3 of them at the same time
That's easy, you can receive another parameter named methodNames of List type.
Utils.wal

defVar --name methodNames --type List --innertype String --parameter
defVar --name methodName --type String --parameter

if --left "${methodName}" --operator "Is_Null_Or_Empty" --negate
	add --collection "${methodNames}" --value "${methodName}"
endIf
foreach --collection "${methodNames}" --variable "${methodName}" --distinct
	//NOTE: if we had meta-programming here, we could validate whether the routine exists before trying calling it
	goSub --label "${methodName}"
endFor


What about parameter validation?
Each method can validate the required parameters and throw errors if they were not specified.
You can also validate whether the methodName or methodNames was passed in:

defVar --name methodNames --type List --innertype String --parameter
defVar --name methodName --type String --parameter

#region validating
case --switches "CaseSwitchesAll"
	when --left "${methodName}" --operator "Is_Null_Or_Empty"
	when --left "${methodNames}" --operator "Is_Empty"
then
	failTest --message "The parameter \'methodName\' or \'methodNames\' is required and was not specified"
endCase
#endregion

if --left "${methodName}" --operator "Is_Null_Or_Empty" --negate
	add --collection "${methodNames}" --value "${methodName}"
endIf
foreach --collection "${methodNames}" --variable "${methodName}" --distinct
	//NOTE: if we had meta-programming here, we could validate whether the routine exists before trying calling it
	goSub --label "${methodName}"
endFor


Here is the full Utils.wal mentioned at the start of the article:
Utils.wal

defVar --name dummyFilePathForPowershell --type String
defVar --name success --type Boolean
defVar --name process --type DataTable --output
defVar --name processId --type Numeric --output
defVar --name processName --type String --output
defVar --name pidText --type String
defVar --name methodName --type String --parameter
defVar --name filePath --type String --parameter
defVar --name fileNameWithoutExtension --type String --output
defVar --name fileName --type String --output
defVar --name fileExtension --type String
defVar --name isDebug --type Boolean --output
defVar --name methodNames --type List --innertype String --parameter
defVar --name environmentVariable --type String --parameter  --output
#region validating
case --switches "CaseSwitchesAll"
	when --left "${methodName}" --operator "Is_Null_Or_Empty"
	when --left "${methodNames}" --operator "Is_Empty"
then
	failTest --message "The parameter \'methodName\' or \'methodNames\' is required and was not specified"
endCase
#endregion

if --left "${methodName}" --operator "Is_Null_Or_Empty" --negate
	add --collection "${methodNames}" --value "${methodName}"
endIf
foreach --collection "${methodNames}" --variable "${methodName}" --distinct
	//NOTE: if we had meta-programming here, we could validate whether the routine exists before trying calling it
	goSub --label "${methodName}"
endFor
beginSub --name CurrentProcess
	writeToFile --value dummy --createrandomfile  --encoding "Default" dummyFilePathForPowershell=value
	
	powerShell --apartmentState "MTA" --script "GET-PROCESS -Id $PID | SELECT -ExpandProperty \"ProcessName\" | OUT-FILE -FilePath \"${dummyFilePathForPowershell}\"" success=success
	readAllText --filepath "${dummyFilePathForPowershell}" --encoding "Default" processName=value
	trimString --text "${processName}" --trimoption "TrimStartAndEnd" processName=value
	
	powerShell --apartmentState "MTA" --script "$PID | OUT-FILE -FilePath \"${dummyFilePathForPowershell}\"" success=success
	readAllText --filepath "${dummyFilePathForPowershell}" --encoding "Default" pidText=value
	trimString --text "${pidText}" --trimoption "TrimStartAndEnd" pidText=value
	convertStringToNumber --culture "en-US" --text "${pidText}" processId=value
	
	addColumn --dataTable ${process} --columnname Pid --type Numeric
	addColumn --dataTable ${process} --columnname "Process Name" --type String
	addRow --valuesmapping "Pid=${processId},Process Name=${processName}" --dataTable ${process}
	
	onError --executenext  --comment "if an error occurs in the \'delete file\' below, ignore it"
	fileDelete --file "${dummyFilePathForPowershell}"
endSub
beginSub --name FileName
	writeToFile --value dummy --createrandomfile  --encoding "UTF8" dummyFilePathForPowershell=value
	
	powerShell --apartmentState "MTA" --script "SPLIT-PATH -PATH \"${filePath}\" -Leaf | OUT-FILE -FilePath \"${dummyFilePathForPowershell}\""
	readAllText --filepath "${dummyFilePathForPowershell}" --encoding "Default" fileName=value
	trimString --text "${fileName}" --trimoption "TrimStartAndEnd" fileName=value
	
	onError --executenext
	fileDelete --file "${dummyFilePathForPowershell}"
endSub
beginSub --name FileNameWithoutExtension
	goSub --label FileName
	getRegex --text "${fileName}" --regexPattern "[a-z0-9\\- ]+(?<extension>\\.\\w+)" --regexOptions "IgnoreCase" --groupname extension fileExtension=value
	replaceText --texttoparse "${fileName}" --textpattern "${fileExtension}" fileNameWithoutExtension=value
endSub
beginSub --name IsDebug
	goSub --label CurrentProcess
	setVarIf --variablename "${isDebug}" --value true --left "${processName}" --operator "Equal_To" --right Studio
endSub
beginSub --name ExpandEnvironmentVariables
	writeToFile --value dummy --createrandomfile  --encoding "UTF8" dummyFilePathForPowershell=value
	
	powerShell --apartmentState "MTA" --script "[System.Environment]::ExpandEnvironmentVariables(\"${environmentVariable}\")  | OUT-FILE -FilePath \"${dummyFilePathForPowershell}\""
	readAllText --filepath "${dummyFilePathForPowershell}" --encoding "Default" environmentVariable=value
	trimString --text "${environmentVariable}" --trimoption "TrimStartAndEnd" environmentVariable=value
	
	onError --executenext  --comment "if an error occurs in the \'delete file\' below, ignore it"
	fileDelete --file "${dummyFilePathForPowershell}"
endSub


I hope you enjoyed this little trick. Take a look at the next article int the series: how to create connectors.


#TaskAutomation(RPA)
#RoboticProcessAutomation(RPA)
#lowcode

Permalink