Funkcje ułatwiają wykonywanie często wykonywanych operacji, takich jak np. sumowanie wartości. Zapobiega to wielokrotnej duplikacji kodu. Funkcje powinny być niezależne oraz jak najbardziej ogólne i elastyczne (możliwość wykorzystania ich w jak największej liczbie przypadków).
System pozwala na rejestrowanie i wykorzystywanie predefiniowanych funkcji zarówno po stronie serwera jak i po stronie przeglądarki.
Funkcja musi zawsze być zarejestrowana po stronie serwera oraz może dodatkowo być zarejestrowana po stronie przeglądarki, gdy chcemy, aby była też tam wykorzystywana. |
Rejestracja funkcji dostępnych w systemie odbywa się podczas uruchomienia systemu oraz dynamicznie dla dynamicznych zasobów, takich jak wtyczki. Za rejestrację i przechowywanie funkcji odpowiada . Podczas rejestracji wyszukiwane są najpierw wszystkie klasy oznaczone adnotacją @
, następnie w tych klasach wyszukiwane są metody oznaczone adnotacją @
i zostają one zarejestrowane jako funkcje.
Poniższy przykład przedstawia definicję prostej funkcji zwracającej wartość wyższej liczby.
@Functions public class BasicFunctions { @Function public Integer maxOf( Integer a, Integer b ) { return Math.max( a, b ); } } |
Zarejestrowana funkcja posiada nazwę, zwracany typ oraz definicję parametrów -> .
Używanie stworzonej funkcji po stronie przeglądarki (na formularzu zadania) wymaga od programisty dostarczenia jej implementacji w języku JavaScript. Taka implementacja wykorzystywana jest podczas dynamicznych obliczeń po stronie przeglądarki klienta.
Funkcje rejestrowane są z wykorzystaniem API (skrócona nazwa
PW.Functions
):
// funkcja "max" która zwraca obiekt typu "float" i przyjmuje 2 parametry typu "float" PW.Functions.register("max", "float", ["float", "float"], function(value1, value2){ return Math.max(value1, value2); }); |
Podczas rejestracji funkcji niezbędne jest zdefiniowanie:
Tak zarejestrowana funkcja zostanie wywołana tylko dla wywołań z argumentami które będą pasowały do zdefiniowanych typów (albo będą tego samego typu albo mogą zostać przekonwertowane).
Oczywiście tak przygotowany skrypt musi zostać wstrzyknięty w obszar formularza zadania. Więcej o wstrzykiwaniu skryptów tutaj. |
Jeżeli podczas rejestracji funkcji nie zdefiniujemy typów parametrów, to funkcja będzie traktowana jako implementacja ogólna. Taka implementacja zostaje wywołana jeżeli nie będzie żadnej innej implementacji funkcji, która może zostać wywołana z aktualnymi parametrami. Parametry przekazane do takiej funkcji są instancjami klasy .
// brak zdefiniowanych typów PW.Functions.register("isVariable", "boolean", function(arg1){ // arg1 jest obiektem klasy PW.component.Arg return !arg1.isArray && arg.value.is("variable"); }); |
Rejestracja funkcji we wtyczce jest taka sama jak zostało to opisane powyżej, jednak należy dodatkowo zaznaczyć, że wtyczka ta udostępnia funkcje do zarejestrowania. W tym celu należy w pliku suncode-plugin.xml dodać wpis:
<functions key="functions" /> |
Taki wpis spowoduje automatyczne wyszukanie wszystkich zdefiniowanych funkcji.
Obecnie funkcje mogą być wykorzystywane na formularzu zadania.
Pobranie funkcji odbywa się za pomocą obiektu :
var fn = Functions.getFunction("maxOf",[1,4]); |
Mając pobraną funkcję z parametrami () możemy ją wywołać:
fn.call(); //returns 4; |
W powyższym przykładzie pobrania funkcji, parametry zostały podane w sposób uproszczony, czyli same wartości bez konkretnego typu. Podczas konwersji typów, mechanizm sam zgadnie typy tych wartości. Gdyby została tam podana wartość tekstowa np.: "zmienna_1", to zostałoby to rozpoznane jako typ string. Jednak w przypadku, gdybyśmy chcieli, aby w tym miejscu znalazła się wartość zmiennej formularzowej o id zmienna_1, to w takim przypadku trzeba podać wartość razem z typem:
var fn = Functions.getFunction("maxOf",[{type: "variable",value: "zmienna_1"}, 4]); //lub var fn = Functions.getFunction("maxOf",[ServiceFactory.getVariableService().get("zmienna_1"), 4]); |
Istnieje również możliwość podania innej funkcji w parametrze:
var fn = Functions.getFunction('maxOf',[{type:"function",value:{name:"maxOf",parameters:[{type:"float",value:8},{type:"float",value:4}]}} ,3]); |
W powyższym przykładzie najpierw zostanie wywołana wewnętrzna funkcja maxOf z parametrami 8 i 4, która zwróci wynik 8 i następnie zostanie wywołana funkcja zewnętrzna maxOf z parametrami 8 i 3, która zwróci wynik 3. Wydaje się jednak, że prostszym i "czystszym" rozwiązaniem jest wywołanie samemu wewnętrznej funkcji:
var fn = Functions.getFunction('maxOf',[Functions.getFunction('maxOf',[8,4]),3]); |