Testing Ascribe Rule Sets

An Ascribe Rule Set lets you programmatically alter the results of linguistic analysis.  To learn more about Rule Sets, see Introduction to Ascribe Rule Sets and Authoring Ascribe Rule Sets.

Your Rule Set may process thousands of findings when you use it in an Inspection. Therefore, it is very important to test your Rule Set carefully to avoid disappointing results.
Suppose we want to create a rule to uppercase our brand name when it appears in the topic of a finding. We write this simple Modify Finding rule:

// Uppercase our brand
f.t.replace("ascribe", "Ascribe");

We intend for this rule to find all occurrences of the word “ascribe” in the topic and replace it with “Ascribe”. We need to test this rule, because it is not correct!

Rule Editor Dialog

On the Rule Sets page of Ascribe, we create a new Modify Finding rule and enter our code:

Dialog for editing a new rule

To test our rule, we need to make sure the Test part of the dialog is expanded as shown above. If not, click on the word Test to expand that part of the accordion. Now enter the properties of the finding you want to use for testing in the top part of the Test pane. I have entered “ascribe” there for the topic.

 

Rule editor dialog with finding properties

Click the Test button below the properties you entered. The properties of the resulting after your rule runs are displayed below the Test button. They are shown in grey if they have not changed, which is what you see in the picture above. Our rule is not working! The resulting finding still has a lower-case topic:

Rule editor dialog - testing

The problem of course is that the replace method of a string returns the modified value. It does not change the value you pass in, so our topic is unchanged. To correct the code, we add an assignment to f.t and retest the rule:

Rule editor dialog with corrected rule

Success! We can now save the rule by clicking the OK button.
You probably noticed that I entered properties for f.r, f.t, f.e, and f.x, even though only f.t is needed for the test. This is because if any of f.t, f.e, or f.x are empty after the rule runs the result of the rule will be ignored. You can try this in the dialog to see for yourself.

Testing Edge Cases

Happy with the result of our Modify Finding rule we may decide to add a Modify Response on Load rule to do the same thing. That way our comments will display our brand name with proper case in the Verbatims pane of CX Inspector. We copy our code into a Modify Response on Load rule, change it to operate on f.r instead of f.t, and give it a test case with a lowercase brand mention. This type of rule receives only f.r when it runs. That’s why the other properties of the finding are not shown in the Test pane:

Modify Response on Load rule

The rule still handles our test case properly, and we may be tempted to consider it completely tested. But we need to test it more. It fails on each of these test cases:

Wow, ascribe is great! I recommend ascribe. ⇒ Wow, Ascribe is great! I recommend ascribe.
Wow, AScribe is great! ⇒ Wow, AScribe is great!
I ascribed his success to luck. ⇒ I Ascribed his success to luck.

The first is because our rule replaces only the first occurrence. The second because our text matching is case sensitive, and the third because we are not replacing only whole words. The simplest fix is to use a regular expression. We can write our rule instead as:

// Uppercase our brand
f.r = f.r.replace(/\bascribe\b/ig, "Ascribe");

The ig flags on the regular expression correct our first two problems, and the use of \b corrects the third problem. Our rule now handles all our test cases correctly.

Rule Debugging and Validation

Using Print()

As you are testing your rules it can be helpful to print out information for diagnostics. The finding object has Print() and Println() methods for this purpose. Here is a rule that captures words in the response and prints each to the test pane when the rule runs:

var m = f.r.match(/\b\w+\b/ig);
for (var i = 0; i < m.length; i++) {
  f.Println(m[i]);
}

If f.r == "Wow, Ascribe is great!", this will print:

"Wow"
"Ascribe"
"is"
"great"

to the Test pane.  The Print() and Println() methods are identical, except Println() appends a newline character to the output. Both methods accepts zero or more parameters. If the parameter list is empty a blank line is output. The Print() and Println() methods have effect only in the Test pane. When the Rule Set is actually used in an Inspection the methods do nothing.  These examples demonstrate the behavior of these methods:

f.Println("Hello world"); // "Hello world"
f.Println(null); // ∅
f.Println(f); // Rule.Finding
f.Println([1,2,3]); // 1,2,3
f.Println(new Date(2018, 0, 1)); // Mon Jan 1 00:00:00 PST 2018

In general Print() writes the result of calling the toString() method on the parameter passed.  However, if the parameter is null the character  is written, and if the parameter is of type String the value is enclosed in quotes, as in the first example above.  If there are embedded quotes in the string they are escaped in the output:

f.Println("Is \"Jane\" your name?"); // "Is \"Jane\" your name?"

If a JavaScript object is passed (not an Array, but a pure Object) it is printed in a style similar to JSON, but only for the top level properties:

f.Println({a: "foo", b: 22, c: [1,2], d: {f: 5}});

produces

{
  "a": "foo",
  "b": 22,
  "c": 1,2,
  "d": [object Object]
}

The behavior changes when more than one parameter is passed.  In that case the values are written sequentially to the output, separate by space characters.  This is useful for annotating the output:

var x = 5;
f.Println("The value of x is", x); // The value of x is 5

Validation

When you click the Validate or OK button in the rule editor dialog, Ascribe runs a few test cases through your rule to guard against rules that will throw errors at runtime. Among the test cases are zero length strings for the various properties of the finding.  Returning to our example above:

var m = f.r.match(/\b\w+\b/ig);
for (var i = 0; i < m.length; i++) {
  f.Println(m[i]);
}

If you try this you will find it works fine when testing, but causes a runtime error when you try to save the rule by clicking OK.  In the rule above, validation using zero length strings will cause the variable m to have a value of null. In the for statement this will case a runtime error of Exception: Object required. As a result, the rule cannot be saved as written. It must be corrected by testing m:

var m = f.r.match(/\b\w+\b/ig);
if (m) {
  for (var i = 0; i < m.length; i++) {
    f.Print(m[i]);
  }
}

In general, when you receive the error Exception: Object required at validation time, you likely need to add a test for a valid object before you access a property or method of the object.

Leave a Reply

Your email address will not be published. Required fields are marked *