Groovy Functions!
Groovers,
I wanted to hack up a way where i could type some groovy code
in a text box and have it compute math functions on arrays of numbers.
Is the code below the best way to do this?
The groovy tutorial is a bit "thin" (to use yawmarks words) in explaining
the ways to get this done.
For those new to Groovy, catch up quickly:
Download
http://groovy.codehaus.org/Download
Install
http://groovy.codehaus.org/Installing+Groovy
Compile + Run Code Below w/ Classpath
-classpath .;"C:\...\groovy-1.0\embeddable\groovy-all-1.0.jar"
Embedding + BSF Tutorial
http://groovy.codehaus.org/Embedding+Groovy
http://groovy.codehaus.org/Bean+Scripting+Framework
About the code:
I dont know how to create and return double arrays in groovy so
i just return a double to test the code : /
For streamlining its possible to wrap the users code in the Class +
Method like:
String code = "public class X implements... " + code + " } \n } ";
but i left that in for clarity.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import groovy.lang.*;
publicclass GroovyTesterimplements ActionListener{
publicstaticvoid main(String[] args){
new GroovyTester();
}
public GroovyTester(){
guiSetup();
}
publicvoid guiSetup(){
numberField =new JTextField("1.0");
numberField.addActionListener(this);
groovyBox =new JTextArea(CODE);
scrollPane =new JScrollPane(groovyBox);
answerField =new JTextField();
contentPane =new JPanel();
contentPane.setLayout(new BorderLayout(2, 1));
contentPane.add(numberField, BorderLayout.NORTH);
contentPane.add(scrollPane, BorderLayout.CENTER);
contentPane.add(answerField, BorderLayout.SOUTH);
window =new JFrame();
window.setContentPane(contentPane);
window.setSize(400, 400);
window.setLocationRelativeTo(null);
window.setVisible(true);
}
publicvoid actionPerformed(ActionEvent e){
if(e.getSource() == numberField){
processFunction();
}
}
publicvoid processFunction(){
Computation c = loadGroovyFunction();
if(c !=null){
double[] values = inputArray();
if(values.length > 0){
double answer = c.compute(values);
answerField.setText("answer: " + answer);
}else{
answerField.setText("no input");
}
}else{
answerField.setText("error");
}
}
publicdouble[] inputArray(){
String[] input = numberField.getText().split("\\s*[, ]\\s*");
for(int i = 0; i < input.length; i++){
System.out.println("Input #" + (i+1) +": '" + input[i] +"'");
}
double[] values =newdouble[input.length];
for(int i = 0; i < input.length; i++){
try{
values[i] = Double.parseDouble(input[i]);
}catch(Exception e){
values[i] = 0;
}
}
return values;
}
public Computation loadGroovyFunction(){
try{
ClassLoader parent = getClass().getClassLoader();
GroovyClassLoader gcl =new GroovyClassLoader(parent);
String groovyCode = groovyBox.getText();
Class clazz = gcl.parseClass(groovyCode);
Object object = clazz.newInstance();
return (Computation)object;
}catch(Exception e){
e.printStackTrace();
returnnull;
}
}
publicstaticinterface Computation{
publicdouble compute(double[] values);
}
JFrame window;
JPanel contentPane;
JTextField numberField;
JScrollPane scrollPane;
JTextArea groovyBox;
JTextField answerField;
publicstaticfinal String CODE =
"\npublic class X implements GroovyTester.Computation{\n"+
"\n" +
"public double compute(double[] values){\n" +
"return values[0] * 2;\n" +
"}\n" +
"\n" +
"}\n";
}
> Is the code below the best way to do this?
Have you considered just using the Groovy console?
http://groovy.codehaus.org/Groovy+Console
> I dont know how to create and return double arrays in groovy
doubleArray = [1.2, 3.4, 5.6]
assert doubleArray == [1.2, 3.4, 5.6]
~
Hey thanks.
If the console is what I think it is it wont work for what im doing.
I want to use this inside an audio program im writing as an effects
module. I can try out different functions and algorithms without
having to recompile the program.
As my inability to create an array shows, i still have quite a bit of
groovy learning to do first...: )
As I read it, you're looking for a way to execute arbitrary code at runtime. If that's not what you're looking for, then I missed it. If it *is* what you're looking for, dig in to the Groovy console. The following article may also help:
http://iterative.com/blog/2007/05/14/embedding-a-groovy-console-in-a-java-server-application
~
>> As I read it, you're looking for a way to execute arbitrary code at runtime.
*bingo*
>> The following article may also help
reading it now. thankx.
You cats are the Groovyest.
I haven't even peeked at it yet.
%
> You cats are the Groovyest.
>
> I haven't even peeked at it yet.
Now that you're the SpringMaster, you should give it a run. Groovy works just fine with Spring, too. ;o)
Here's a good, quick little overview:
http://www.ibm.com/developerworks/library/j-pg09196.html
~
Is there a way to "unload" a class?
the groovyclassloader docs dont specify a way
http://groovy.codehaus.org/api/groovy/lang/GroovyClassLoader.html
And for the "Class parseClass(String text)" method they dont specify
what happens when you reload the same class over and over.
Is it saving every version of the class in memory or is the garbage
collector removing the old ones?
If it works like in Ruby the class when reloaded replaces the previous version.
What happens to existing instances of that class already in memory I've not gotten around to trying (but I expect it won't be pretty).
And no, I've not gotten around to Groovy either. For now I'm still trying to figure out what the Ruby hype is all about, and at my age I can only analyse one hype at a time :)
> Is there a way to "unload" a class?
Not that I'm aware of, but that doesn't mean much.
~
Anyone have any clue why this line doesnt work
when typed into the "groovy box":
double[] result = new double[]{ 1, 2, 3 };
this works:
double[] result = [ 1, 2, 3 ];
double[] result = new double[3];
i prefer the "=[1,2,3]" way, but i thought groovy accepted valid
java code?
> Anyone have any clue why this line doesnt work
> when typed into the "groovy box":
>
> double[] result = new double[]{ 1, 2, 3 };
Yes, that's not valid Groovy syntax. Note that "d = [1, 2, 3]" doesn't declare a double array. It declares a list.
d = [1, 2, 3]
assert d instanceof ArrayList
> i prefer the "=[1,2,3]" way, but i thought groovy accepted valid
> java code?
No, Groovy is a different language. The syntax is similar, but it's not the same.
~
well i guess the thing that is throwing me off (aside from
not RTFM, lol) is that this:
result = [1,2,3];
does NOT work. only:
double[] result = [1,2,3];
works. so is it a list, is it a double[], is it java, is it groovy, lol?
wtf is going on?
EDIT: ah, i was missing the elusive "def" keyword!
http://groovy.codehaus.org/Collections
> well i guess the thing that is throwing me off (aside
> from
> not RTFM, lol) is that this:
>
> result = [1,2,3];
>
> does NOT work.
Sure it does.
result = [1, 2, 3]
assert result == [1, 2, 3]
What problem are you having?
> EDIT: ah, i was missing the elusive "def" keyword!
> http://groovy.codehaus.org/Collections
The def keyword isn't strictly necessary here.
~
Well, the tutorials give a lot of the code as you would script with
Groovy but I guess its slightly different for the classes.
Because:
result = [1, 2, 3]
assert result == [1, 2, 3]
does NOT work.
public class X implements GroovyTester.Computation{
public double compute(double[] values){
result = [1,2,3];
// assert result == [1, 2, 3];
return 1;
}
}
Throws this error:
Exception in thread "AWT-EventQueue-0" groovy.lang.MissingPropertyException:
No such property: result for class: X
"def" fixes it though.
Why is all the tutorial code littered with asserts?
> I guess its slightly different for the classes.
Ah, sorry. I didn't know you were trying to define it as a local variable. Here's an example, without the need for all the extra declarations:
d = [1, 2.3, 4]
assert 7.3 == new X().compute(d)
class X {
public double compute(values) {
double result = 0
values.each { result += it }
return result
}
}
> Why is all the tutorial code littered with asserts?
Inline testing.
~
Wow. It works great. This is so much fun!
public double[] compute(double[] values){
def square = { it * it }
def result = [1,2,3]
result.each{ println "Item: $it" }
result = result.collect(square)
result.each{ println "Item: $it" }
return [1]
}
Is there a collect(closure) function for Lists that will change the values
in place instead of returning a new array?
> Wow. It works great. This is so much fun!
Out of curiosity, why are you bothering with defining a method in a class at all?
> Is there a collect(closure) function for Lists that will change the values in place instead of returning a new array?
Not to my knowledge, no.
~
I just want to write a chunk of code and have it process
an array of numbers - over and over and over again.
I figured that loading the code as a class would be faster than
evaluating a GroovyScript over and over.
Dude, im all new to this so i have no clue. You've sugggested
the groovy console a few times and i read that article you posted but
that seems like overkill. Theres XML and networking involved...
The GroovyScriptEngine and GroovyObject loader require a Script
file but it'd be annoying to save off a new file every time you make a
small change to the code.
Plus the GroovyClassLoader already comes with a parseClass
method for loading Java and Groovy source from a String instead
of a File.
http://groovy.codehaus.org/api/groovy/lang/GroovyClassLoader.html
I believe the GroovyShell (from the tutorial page) reparses and
evaluates a script provided as a String every time it is run.
For complicated algorithms that might be too much.
What do you have in mind?
http://groovy.codehaus.org/Embedding+Groovy
> why are you bothering with defining a method in a class at all?
actually, the short answer may be that the tutorial told me to,
so i can use it as an Interface:
Class groovyClass = loader.parseClass(code);
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
Object[] args = {};
groovyObject.invokeMethod("run", args);
versus
Class clazz = gcl.parseClass(code);
Object aScript = clazz.newInstance();
MyInterface myObject = (MyInterface) aScript;
myObject.interfaceMethod();
> What do you have in mind?
It just depends on what you want to do. You integrate the Groovy Shell, the Groovy Console, Groovy Script objects, etc.
Example:s = '''
def mass = 22.3
def velocity = 10.6
mass * velocity**2 / 2
'''
def kineticEnergy = evaluate(s)
assert kineticEnergy == 1252.814
> Dude, im all new to this so i have no clue.
Then don't start with some huge project. Give yourself time to play around.
~
>> Then don't start with some huge project. Give yourself time to play around.
I am playing! : )
I just got VSTs working in my audio program pet project.
This groovy class loading will let me write sounds in program.
Im very excited!