Tora is a Gosu extension library that allows for seamless interaction with javascript resources, leveraging Gosu's Open Type System and the Java Nashorn project.
The library supports the use of javascript programs from Gosu, the use of ES6-flavored javascript classes from Gosu, the use of Gosu (and Java) classes from javascript, as well as the creation of type-safe javascript expressions for use in Java or Gosu, as a scripting layer.
This library is sponsored and supported by Guidewire Software
Tora makes standard ES5-style Javascript programs available as types in Gosu.
The javascript program is evaluated when the type is first accessed. Top level functions are accessible as static methods on the program type.
Here is an example top-level function found in ExampleProgram.js
:
function hello(name) {
return "Hello " + name;
}
This function could be invoked from Gosu like so:
print( ExampleProgram.hello("Gosu") )
Parameters and the return type of javascript functions are all of type dynamic.Dynamic
which is a special Gosu type that allows for dynamic type behavior.
Top level variables in javascript programs are treated as global variables and will retain their values between evaluation. Given this function:
var i = 0;
function nextNum() {
return i++;
}
The following code
print( ExampleProgram.nextNum() )
print( ExampleProgram.nextNum() )
will print
0.0
1.0
Javascript classes are exposed as regular classes in Gosu. They have the same functionallity as Java classes, including constructors, methods, static methods, and properties.
Javascript: foo.js
class Foo {
//Constructor
constructor(a) {
this.foo = a;
this._bars = 5;
}
//Methods
function bar() {
return this.foo * 2;
}
function baz(a,b) {
return a+b + this.foo;
}
//Static Methods
static hello() {
return "hello";
}
//Properties
get bars() {
return this._bars*2;
}
set bars(a) {
this._bars = a;
}
}
The constructor is called when a new object is created. It initializes the properties within the object.
Javascript:
class Foo {
constructor(a) {
this.bar = a;
}
}
Gosu:
var foo = new Foo(5); // Creates new Foo object and sets this.bar to a
Methods are functions that are assigned to classes. They can interact with properties of the class and call other internal methods.
Javascript:
class Foo {
constructor(a) {
this.foo = a;
}
function bar() {
return this.foo * 2;
}
}
Gosu:
var foo = new Foo(21);
print(foo.bar); // returns 42
Javascript:
class Foo {
constructor(a) {
this.foo = a;
this._bars = 5;
}
static function staticFoo() {
return 42;
}
}
Gosu:
print(Foo.staticFoo()); // Prints 42
Classes can have getter and setter properties which abstract the properties held within the class.
Javascript:
class Foo {
constructor(a) {
this.foo = a;
this._bars = 5;
}
get bars() {
return this._bars*2;
}
set bars(a) {
this._bars = a;
}
}
Gosu:
var foo = new Foo();
foo.bars = 21;
print(foo.bars) // Prints 42
Javascript templates are supported as first class citizens. A Javascript String Template is a file that ends in the .jst extension.
Javascript Template: SampleJSTemplate.jst
<%@ params(names) %>
All Names: <%for (var i = 0; i < names.length; i++) { %>
${names[i]}
<% } %>
The template declares the parameters using the <%@ params() %>
directive, and can import Java/Gosu classes using
the <%@ import %> directive.
Javascript statements can be added between the <%
and %>
punctuators, which are evaluated as Javascript but
added directly to the generated string.
Javascript expressions can be added either between the ${
and }
punctuators or the <%=
and %>
punctuators,
and are evaluated and added to the generated string.
Javascript templates can then be rendered from Gosu as so:
Gosu:
var str = SampleJSTemplate.renderToString({"Carson", "Kyle", "Lucca"});
print(str)
Javascript classes can be accessed using the same syntax as Gosu classes.
Gosu:
var foo = new Foo(10);
print(foo.bar()); // 20
print(foo.bars); // 5
foo.bars = 20;
print(foo.bars) // 40
print(Foo.hello()) // Hello
The (non-standard javascript) import statement is used to extend gosu and java classes with javascript methods.
Here is some example javascript: hello.js
import java.util.ArrayList;
function hello() {
var arrlist = new ArrayList();
arrlist.add(1);
arrlist.add(2);
arrlist.add(3);
print(arrlist.toArray(new Integer[arrlist.size()]));
}
This can be invoked from Gosu like so:
hello.hello(); //prints [1,2,3]
The import statement in tora acts like the java import statement, not the (unsupported) javascript version.
Java classes can be extended using javascript, allowing for the creation of modified classes. One known limitation is that the constructor of the superclass cannot be overwritten.
Javascript:
import java.util.ArrayList;
class sizePrints extends ArrayList {
size () {
print(super.size());
}
}
Gosu:
var sizePrintsArrayList = new sizePrints();
sizePrintsArrayList.add(1);
sizePrintsArrayList.add(2);
sizePrintsArrayList.add(3);
sizePrintsArrayList.size(); // Prints 3
The current implementation of Nashorn is not yet stable for multi-threading. Although it allows for multi-threading, the implementation is very slow when it comes to creating and deleting objects.
Users should not attempt to access any Nashorn objects from multiple threads.
In order to allow for greater control and readability, tora allows for specifying the types of variables that can be parameters and return types. The supported types include any in the standard java.lang.* package, however those found in the java.util.* packages must be imported.
Javascript:
import java.util.ArrayList;
class Sample {
constructor(a : String) {
this.foo = a;
}
foo (bar: String, baz : Integer) : ArrayList {
var arrlist = new ArrayList();
for(var i = 0 ; i < baz ; i ++) {
arrlist.add(bar);
}
return arrlist;
}
}
Gosu:
var sample = new Sample();
print(foo("Hello", 5)) // ["Hello","Hello","Hello","Hello","Hello"]
Tora supports the use of ES6 Arrow Functions inside any Javascript program or class.
Javascript:
//Arrow function expression
function filterEvens(list) {
return list.filter( a => a % 2 == 0);
}
//Arrow function statements
function incrementList(list) {
return list.map( a => {return a + 1});
}