Привязка значений к переменным, указанным в скрипте - PullRequest
0 голосов
/ 07 октября 2011

Я создаю GWT-версию библиотеки Java, которая поддерживает javax.script.ScriptEngine для динамической оценки функций через Javascript, например,

o => o % 2 == 0

где во время выполнения значение "o" определяется с помощью javax.script.Bindings (часть o =>, конечно, удаляется).

Проблема в том, как я могу получить тот же эффект из GWT? Я использую нативную функцию

native Object nativeEval(String script) /*-{
    return $wnd.eval(script);
}-*/

nativeEval("o % 2 == 0");

Но как мне связать значение с идентификатором "o"?

Ответы [ 3 ]

0 голосов
/ 10 октября 2011

Наверное, я нашел решение:

import javax.script.bindings.Bindings;
import javax.script.bindings.SimpleBindings;

int bindSequence;

native void prepareOnWindow(int index) /*-{
    $wnd["mylib_bindings_" + index] = new Array();
}-*/;
native void setOnWindow(int index, String name, Object value) /*-{
    $wnd["mylib_bindings_" + index][name] = value;
}-*/;
native void clearOnWindow(int index) /*-{
    $wnd["mylib_bindings_" + index] = null;
}-*/;
native Object invoke(String script) /*-{
    var result = $wnd.eval(script);
    if (typeof(result) == "boolean") {
        return result ? @java.lang.Boolean::TRUE : @java.lang.Boolean::FALSE;
    } else
    if (typeof(result) == "number") {
        return @java.lang.Double::valueOf(D)(result);
    }
    return result;
}-*/;
public Object invoke(String script, Bindings bindings) {
    int seq = bindSequence++;
    try {
        StringBuilder script2 = new StringBuilder();
        prepareOnWindow(seq);
        for (Map.Entry<String, Object> e : bindings.entrySet()) {
            setOnWindow(seq, e.getKey(), e.getValue());
            script2.append("var ").append(e.getKey()).append(" = ")
            .append("window[\"mylib_bindings_\" + ").append(seq)
            .append("][\"").append(e.getKey()).append("\"];\r\n");
        }
        script2.append("\r\n").append(script);
        return invoke(script);
    } finally {
        clearOnWindow(seq);
    } 
}

void testing() {
    Bindings b = new SimpleBindings();

    b.put("o", 1);

    Window.alert(invoke("o", b).toString());

    b.put("o", "Hello world");

    Window.alert(invoke("o", b).toString());

    b.put("o", 2);

    Window.alert(invoke("o % 2 == 0", b).toString());
}

Идея состоит в том, чтобы установить пары имя-значение в общедоступном объекте, например в окне, и изменить скрипт, чтобы получить из него переменные. Чтобы разрешить вызов с возможностью повторного входа, привязки хранятся под постоянно увеличивающимся порядковым номером.

0 голосов
/ 10 октября 2011
new Function("o", "return (" + expressionThatUsesO + ")")(o)

Если expressionThatUsesO равно "o % 2", то это эквивалентно глобальной функции, которая немедленно вызывается

(function (o) { return o % 2; })(o)

Для справки: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function:

new Function ([arg1[, arg2[, ... argN]],] functionBody)

Параметры

arg1, arg2, ... argN

Имена, которые будут использоваться функцией в качестве имен формальных аргументов. Каждая из них должна быть строкой, соответствующей действительному идентификатору JavaScript, или списком таких строк, разделенных запятой; например "x", "theValue" или "a,b".

functionBody

Строка, содержащая операторы JavaScript, содержащие определение функции.

0 голосов
/ 07 октября 2011

Чтобы передать значения идентификатору "o":

public native void define(String handle, Object o) /*-{
    eval("var " + handle+ "="+ o);
}-*/;
public native boolean nativeEval(String script) /*-{
    return eval(script);
}-*/;

И затем вызвать его:

String script = "o % 2 == 0";
define("o",2);
Window.alert(nativeEval(script)+"");
define("o",3);
Window.alert(nativeEval(script)+"");
...