Reflex Modules - RapturePlatform/Rapture GitHub Wiki
Modules
Reflex has the concept of modules
that can be used to extend the functionality of Reflex through custom Java code that can be deployed alongside the environment. In this way application developers can create (or link to) more complex concepts and can interact with those libraries through normal Reflex scripts. As an example, in a Financial services application using Reflex the complete analytics library was exposed to Reflex users using this technique.
Use in Reflex
In Reflex a module is referenced using an import
statement. This statement takes the following form:
import "classname" as "modulename" [with ( parameters ) ];
The classname refers to a Java class that is on the classpath loaded by Reflex, and the module name is an alias for this module that is used later on in scripts. The classname can omit 'reflex.module' if the class is in that package already. The module name will be converted to a normal Java convention of having first letter capitalization. The module can be initialized with parameters if necessary. To call a function in a module a script writer uses the $ prefix on the module name, like in the example below:
import testModule as test;
answer = $test.addOne(5);
assert(answer == 6);
This example refers to a testModule that will be explored in later sections.
Creating a module
Classes that are referred to in import statements must implement the reflex.importer.Module
interface. This is reproduced below:
public interface Module {
ReflexValue keyholeCall(String name, List<ReflexValue> parameters);
boolean handlesKeyhole();
boolean canUseReflection();
void configure(List<ReflexValue> parameters);
void setReflexHandler(IReflexHandler handler);
}
There are two ways a developer can create a module -- using a keyhole interface and using reflection. A module could support both but would normally support just one. Reflection is preferred for ease of development and rapid extension at a small cost of Java reflection.
Keyhole module
A keyhole module would return true
for the method handlesKeyhole
. If a module returns true to this method Reflex will invoke the keyholeCall method for each module method invocation in a Reflex script. In the example above, a call to $test.addOne(5)
would be translated into the following call:
List<ReflexValue> params = new ArrayList<ReflexValue>();
params.add(new ReflexValue(5));
ReflexValue result = module.keyholeCall("addOne", params);
In this way the implementation of the keyholeCall
method must test the value of the name
parameter to switch to the appropriate implementation.
Reflection module
A reflection module would return true
for the method canUseReflection
. If a module returns true to this method Reflex will look for a method with a very specific signature in the class implementation of the module. If that method exists it will be invoked. The signature is for a method that returns a ReflexValue
and takes a single List<ReflexValue>
parameter. As an example, the implementation of the testModule
demonstrated above could be completely implemented by the following Java class:
package reflex.module;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import reflex.IReflexHandler;
import reflex.ReflexException;
import reflex.importer.Module;
import reflex.value.ReflexValue;
public class TestModule implements Module {
@Override
public ReflexValue keyholeCall(String name, List<ReflexValue> parameters) {
return ReflexValue.VOID;
}
@Override
public boolean handlesKeyhole() {
return false;
}
@Override
public boolean canUseReflection() {
return true;
}
@Override
public void configure(List<ReflexValue> parameters) {
}
@Override
public void setReflexHandler(IReflexHandler handler) {
}
public ReflexValue addOne(List<ReflexValue> parameters) {
if (parameters.size() != -1) {
throw new ReflexException(-1, "addOne needs one parameter!");
}
Integer v = parameters.get(0).asInt();
return new ReflexValue(v.intValue() + 1);
}
}
In the listing above we check the size of the parameters and throw a ReflexException
if incorrect, and then use simple mathematics to return the result. Not that the asInt
method on ReflexValue will throw an exception if the value passed is not an integer (or cannot be coerced to an integer) and this is exactly the behavior we want -- Reflex Exceptions are handled correctly by the interpreter and can be caught by \Reflex exception handlers.
Built-in modules
Reflex has a number of built-in modules that have been created to extend Reflex using commonly used third party (and open source) libraries. All are implemented as reflection based modules.
Statistics module
The statistics module draws on the Apache Commons Math library. The main function computes the statistics associated with a list of values and is called "statistics". It returns a map with three values, the "mean", the "std" (standard deviation) and "median" (the value of the 50th percentile).
The other three functions in the module work with "Frequency" objects. A frequency object is created using the frequency function - it returns a special Reflex Value that can be passed into the other two methods as the first value. The other two methods calculate the number of values that match the value passed (frequency_count
) and the cumulative percentage of values up to a value (frequency_cum_pct
). This is best illustrated by example:
import reflexStatistics as stat;
points = [ 1,2,3,4,5,6,7,8,9,10,100];
res = $stat.statistics(points);
println("Result is " + res);
multiplePoints = [ 1,2,1,1,1,1,2,1,2,4,5,1,2,3,5];
freq = $stat.frequency(multiplePoints);
println("Count of 1 in frequency is " + $stat.frequency_count(freq, 1));
for i = 1 to 5 do
println("CumPct at " + i + " is " + $stat.frequency_cum_pct(freq, i));
end
The result of running this script would yield the following output:
Result is {median=6.0, std=28.637229424141385, mean=14.09090909090909}
Count of 1 in frequency is 7
CumPct at 1 is 0.4666666666666667
CumPct at 2 is 0.7333333333333333
CumPct at 3 is 0.8
CumPct at 4 is 0.8666666666666667
CumPct at 5 is 1.0
Gamma module
The Gamma module uses the Apache Commons Math library to compute values relating to the Gamma
function and its derivatives.
Gamma function
The gamma function (gamma
) takes zero or one parameter. In its no parameter form, it returns the value of the Euler-Mascheroni constant (also known as Euler's constant), and referred to as gamma. With one parameter it reurns the gamma function on the parameter.
DiGamma function
The digamma function (digamma
) takes one parameter and returns the digamma function on the parameter.
TriGamma function
The trigamma function (trigamma
) takes one parameter and returns the trigamma function on the parameter.
Erf module
The Erf module uses the Apache Commons Math library to compute Error Function values. It has two functins - erf
returns the error function of its parameter, and erfc
returns the error function coefficient of its parameter.
Math module
The math module provides standard support through the Java Math package. The functions exposed are shown in the table below:
Function | Parameters | Description |
---|---|---|
pi | none | Returns the constant pi |
e | none | Returns the constant epsilon |
abs | value | Returns the absolute value of a number |
acos | value | Returns the arc-cosine of the number |
asin | value | Returns the arc-sine of the number |
atan | value | Returns the arc-tangent of the number |
atan2 | x,y | Returns the arc-tangent "2 parameter" result of the (x,y) values passed |
cbrt | value | Returns the cube root of the number |
ceil | value | Returns the value rounded up to the nearest integer |
cos | value | Returns the cosine of the value in radians |
cosh | value | Returns the hyperbolic cosine of the value |
exp | value | Returns epsilon raised to the power of the value |
expm1 | value | Returns epsilon^x - 1 |
floor | value | Returns the value rounded down to the nearest integer |
hypot | x,y | Computes sqrt ( x^2 + y^2 ) |
log | value | Computes the natural logarithm of the value |
log10 | value | Computes the base-10 logarithm of the value |
log1p | x | Computes log(1+x) |
max | x,y | Returns the maximum of x or y |
min | x,y | Returns the minimum of x or y |
pow | x,y | Returns x^y |
sin | value | Returns the sine of the angle in radians |
sinh | value | Returns the hyperbolic sine |
sqrt | value | Computes sqrt x |
tan | value | Computes the tangent of the angle in radians |
tanh | value | Computes the hyperbolic tangent |
degrees | value | Converts radians to degrees |
radians | value | Converts radians to degrees |