5
$\begingroup$

I'm working on a project that allows for executing arbitrary, user-defined Mathematica scripts. It's an internal tool running on a trusted, local network. It's basically a web interface to Mathematica.

For every user-defined package I import, I can run Names to get the list of public functions, which I can display in a combobox. Once the user selects a function to call, I would like to have specific widgets to select the appropriate values for the arguments.

For example, f could have two arguments: the name of a column in a database table and a list of WHERE conditions. I would then show a combobox with all the column names and an expandable list of text boxes for conditions.

There's this nifty countArgs function which I can use to get the number of parameters, but I'm stuck on adding type information on each parameter. I have two ideas right now:

  • For each function f in a package, look for a fMeta and standardize a way of returning the meta information required.
  • Hijack f::usage, embed the information there and parse it, giving something like "name1,type1;name2,type2;;actual usage".

I'm probably going for the first option. Anybody has something smarter than this?


Here's a bit more information on the setup:

enter image description here

The core of the tool is a C++ program. It spawns Mma kernels running on the local machine using WSTP and connects to a Postgres database using libpq. Mma will also connect to the database using DatabaseLink. The C++ program also runs a fastcgi server and serves web pages as its main user interface.

As a simpler example, users can enter verbatim Mma scripts on the web page and execute them. Here's what would happen:

  1. A user types the Mma code in a textbox on the web page and submits it;
  2. It gets posted using AJAX to the C++ program, which picks it up through its fastcgi server;
  3. The C++ program then passes ExportString[ToExpression[code], "SVG"] to Mma and sends back the SVG to the web page.

Because the results of Mma are always exported as images, I can't use any of its interactive features like FormObject. As for webMathematica, my understanding is that it's just a front end to Mma, which is too low level for me. The whole point of this tool is to give easy access to high level operations to a couple of stats guys so they don't have to copy paste from SPSS to Excel to PowerPoint to Excel to Excel to PowerPoint.

As for calling a function from the script instead of looking for a function + "Meta", it's a good idea, but I haven't set up two way communication between the C++ program and Mma. I'm not even sure it's possible. I would have to check whether I can get Mma to somehow call into the C++ code, but it looks more complicated than the other way around for now.

$\endgroup$
  • $\begingroup$ It seems you need your own type system, with very specific requirements, which arbitrary Mathematica function will not fulfill. Maybe you could create your own package, and require every user defined package to import it. It could define some kind of registering function: RegisterWebFunction[f_Symbol, argTypes_List] := ... that would accept only very specific type declarations. Then you could display only user defined functions explicitly registered with RegisterWebFunction. ... $\endgroup$ – jkuczm Feb 7 '17 at 15:36
  • $\begingroup$ But details depend on how much, in your system, will be actually done in Mathematica, and how much outside. In your web interface are you using FormObjects, Wolfram Cloud, webMathematica? You mentioned accessing database, are you using DatabaseLink? $\endgroup$ – jkuczm Feb 7 '17 at 15:36
  • $\begingroup$ @jkuczm I've updated my answer with more info. $\endgroup$ – isanae Feb 8 '17 at 0:11
  • $\begingroup$ In your simpler example, as I understand, there's no need for any function metadata, since web interface always has the same textarea. But if you want to display different widgets, based on Mathematica code, then you'll need to somehow transfer information from Mathematica to C++ (which governs interface creation), no matter how this information is stored in Mathematica. $\endgroup$ – jkuczm Feb 9 '17 at 22:48
  • $\begingroup$ @jkuczm The example was just to explain the design. I know I need to "somehow" transfer that info and since I expect Mma->C++ to be more complicated than C++->Mma, I thought calling a function by adding "Meta" to its name would be the simplest. If nobody else has other ideas, that's what I'll go with. $\endgroup$ – isanae Feb 9 '17 at 22:54
0
$\begingroup$

You could create special registering function that would accept function name and necessary metadata describing its arguments. In web interface you would provide only functions that were explicitly registered.

Sketch of package providing such function could look like this:

BeginPackage@"WebFunctions`"; Unprotect@"`*"; ClearAll@"`*"

RegisterWebFunction::usage = "\
RegisterWebFunction[f, <|\"label1\" -> meta1, \"label2\" -> meta2, ...|>] \
registers function f as web accessible, having arguments described by given \
label -> metadata entires.";

UnregisterWebFunction::usage = "\
UnregisterWebFunction[f] \
removes function f from web accessible functions.";

WebFunctionsForms::usage = "\
WebFunctionsForms[] \
returns list of active forms that, when submitted, applies registered web \
function to values from submitted form.";

Begin@"`Private`";

$webFunctions = <||>;

RegisterWebFunction[f_Symbol, argTypes_Association] :=
    AssociateTo[$webFunctions, f -> argTypes]

UnregisterWebFunction[f_Symbol] := KeyDropFrom[$webFunctions, f]

applyToAssocValues[f_] := f @@ Values@#&

WebFunctionsForms[] :=
    KeyValueMap[
        FormFunction[
            FormObject[#2,
                AppearanceRules -> "Title" -> "Function: " <> SymbolName@#1
            ],
            applyToAssocValues@#1
        ]&,
        $webFunctions
    ]

End[]; Protect@"`*"; EndPackage[];

Example of function registering:

f // ClearAll
f[x_Integer?Positive, y_?BooleanQ] := {"f function result", x, y}
f~RegisterWebFunction~<|"x" -> Restricted["Integer", {1, Infinity}], "y" -> "Boolean"|>

g // ClearAll
g[str_String] := {"g function result", str}
g~RegisterWebFunction~<|"str" -> "String"|>

Forms related to registered functions:

WebFunctionsForms[]

print screen of forms

Of course format of second argument of RegisterWebFunction and of value returned by WebFunctionsForms should be adapted to your needs.

$\endgroup$
  • $\begingroup$ I haven't forgotten this question, I just didn't get around to implementing this yet. I will eventually! $\endgroup$ – isanae Apr 11 '17 at 23:24
  • $\begingroup$ I've decided against integrating Mathematica in this project for a variety of reasons. I've accepted your answer because it is unlikely that I'll ever revisit this. $\endgroup$ – isanae May 16 '17 at 22:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.