Selectors
| < Transformers | Executors > |
What are selectors?
Selectors are qualifiers that have a filter function. They typically apply only to collection types and can be combined using logical operators. A selector specifies a condition that must be satisfied by an object to be included in the result collection. In theory, you could have a selector that creates a result collection containing more objects than the input collection. In practice, selectors always act as filters, i.e. they create a result collection that contains at most the input collection's elements, but usually fewer.
Take the following integer list as an example. Because we are only interested in the even integers we write:
C:\terp\bin>terp -e "{0,1,2,3,4,5,6,7,8}[even]"
02468
The resulting list had to be converted to a string for output purposes, so we ended up with a string concatenation of the even integers in the list. even is a built-in numeric selector, as is odd.
There are also comparison selectors that take one argument in addition to the implicit element to be tested. If you wish to select only elements greater than (gt) or less than (lt) a reference element, you can write:
C:\terp\bin>terp -e "{0,1,2,3,4,5,6,7,8}[gt(4) && lt(7)]"
56
The built-in comparison selectors are called lt (less than), le (less equal), eq (equal), ge (greater equal), gt (greater than), and ne (not equal). Each one takes one argument that has to be comparable to the elements in the collection.
Built-in selectors
The following table lists the built-in selectors that come with terp.
| Name | Arguments | Description |
|---|---|---|
| dir | none | Selects File objects that are directories. |
| empty | none | Selects null or objects that convert to the empty string. (Most often used negated, as in !empty) |
| even | none | Selects numeric objects whose truncated integer representation is even. |
| eq | Object | Selects objects satisfying a == comparison to the given object. |
| executable | none | Selects File objects that are executable. |
| file | none | Selects File objects that are regular files. |
| ge | Object | Selects objects satisfying a >= comparison to the given object. |
| gt | Object | Selects objects satisfying a > comparison to the given object. |
| hidden | none | Selects File objects that are hidden. |
| jar | none | Selects File objects whose lowercased name ends with ".jar". |
| le | Object | Selects objects satisfying a <= comparison to the given object. |
| lt | Object | Selects objects satisfying a < comparison to the given object. |
| le | Object | Selects objects satisfying a <= comparison to the given object. |
| match | String, Pattern | Selects String objects that match the given pattern. |
| ne | Object | Selects objects satisfying a != comparison to the given object. |
| odd | none | Selects numeric objects whose truncated integer representation is odd. |
| readable | none | Selects File objects that are readable. |
| startswith | String | Selects String objects that start with the given string. |
| writable | none | Selects File objects that are writable. |
| zip | none | Selects File objects whose lowercased name ends with ".zip".. |
Custom selectors
You can also build your own selectors by taking advantage of the automatically defined this variable. this always refers to the element that is currently being analyzed. If you wanted to select from a list of strings the ones that start with an 'a', you could write:
C:\terp\bin>terp -e "{'also','end','absolute'}[this.charAt(0)=='a']"
alsoabsolute
Custom selectors like the one above rely on one crucial assumption: it must be clear and obvious to the expression evaluation engine that the selector expression resolves to a boolean value.
In the above example, this is the case because the result of the == operator is guaranteed to be boolean. Simply calling a method that returns a boolean value is not good enough. You will have to use a logical or a comparison operator to make your intent clear. The reason for this lies in the dynamic nature of terp's expression evaluator. Lists and collections are not limited to elements of one type. A list might for example contain some string type elements and some other lists. A method that is declared to return a boolean value for one type of element might return a different value for another type of element. This is why we don't take method return types into account in the determination of whether an expression is boolean in nature or not.
So how can you make methods work in selectors? Take the example of invoking startsWith() on this. The String.startsWith() function returns a boolean value, so you might expect being able to use it directly in a selector expression. This is not the case. You will have to use a comparison to make it clear that your intent is selection and not formatting or transformation. You could for example write:
C:\terp\bin>terp -e "{'also','end','absolute'}[this.startsWith(\"a\")==true]"
alsoabsolute
