Hello all!
Today I would like to enlighten a bit on how to
use ScriptedServices inside of Evaluation service
Scripted Services
- provided through a separated *.js file(s), located under the config/reports
folder - processed and Injected before report creation
- In case same function defined within multiple files (name +
number of arguments) then the X for the m2doc (Someone can confirm)
The registering follows the name optionally suffixed with number
if it needs more then 1 argument ( triggered object)
serviceName:function(dummy){…},
serviceName2:function(dummy,arg1){…}
Evaluation service- Available within {m:} blocks
Needs an Object as a trigger =>
{m: ‘hello’.eval(‘self;’)}
Since 2024R2+ Allows to provide additional ( up to 5 arguments
as objects) =>
{m:‘Hello’.eval(‘[self,p2,p3,p4,p5]’,arg1,Sequence{1,2},arg3,arg4,arg5).asList()}
Now a simple question, can we reuse objects/services
defined in the Scripted Service file(s) inside of the Evaluation Service ?
Answer is yes.
The Scripted Services object need just a tiny update with addition
of another function that will return the ScriptedService object
({
customServices:function(theObject){
return this;
},
// another scripted services
});
Now how to use it ? Very Simple, just call service and provide the object it as an
argument for an eval()
Passing services object as self ( callee)
{m: ''.customServices().eval('Object.keys(self).sort();').asList()->sep('[','|','']')}
Passing services object as an additional argument
{m: myVariable.eval(‘Object.keys(p2).sort();',''.customServices).asList()->sep('[','|',']')}
Lets take an example from M2DocSample Reports #F: Traceability matrix with JavaScript
A small modification of the code inside of the m2docMatrixServices.js
({
/**
* Function to return this Services Object
**/
customServices:function(dummy){
return this;
},
/**
* Gets a {@link MTable} with the given label and an empty {@link MCell}.
*/
tableEmptyCell : function (theString) {
var table = new MTableImpl;
…
});
Resulting output of the m2doc statements with
eval :
[customServices|matrixEventsTracedRequirements2|tableEmptyCell|traceabilityMatrix5]
Now onto the usage in the evaluation service. One
may have noticed that the name of the service functions will be handled
differently.
In m2doc the suffixed number is removed from a registered service while
in the JS evaluation you see the full service name.
Simply the JS object is
visible to the JS evaluation inside of evaluation service as defined in the
*.js file
So in order to use the function with more than one
argument one need to call it by original name.
M2Doc call
{m: 'dummy'.matrixEventsTracedRequirements(myEvents)}
M2doc via eval
{m: myEvents.eval('p2.matrixEventsTracedRequirements2(\”dummy string\”,self);')}
What are the potential benefits ?
- Some bind() classes/context objects can be reused inside of
the eval service even without EXPERIMENTAL pragma - Allowing to call the service with variable (not all) arguments
- Reusing some sophisticated code /functions defined in the
service files
Better performance in case a load of external js file is
needed ( 1x load inside of the service defining file vs. several load() in multiple evaluation
service statements inside of m2doc- Others??
NOTE: In case of multiple service files make sure
that the service return function has some self-explanatory, unique name across
files . i.e matrixServices tableServices, haraServices
Alos in order not to waste a lot of eval service
=> use Sequence or Map(will be available in 2025R2??) to pass multiple service Objects:
Passing multiple Services as Collection
{m: myObject.eval('Object.keys(p2.toArray()[0]);',Sequence{''.matrixServices(),''.tableServices()} ).asList() }
Passing multiple Services as Map
TBD (once implementation available)
Marian