groovy

Re-write InteractiveShell (aka. groovysh) in Groovy

Details

  • Type: Improvement Improvement
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Fixed
  • Affects Version/s: None
  • Fix Version/s: 1.1-rc-1
  • Component/s: None
  • Labels:
    None
  • Number of attachments :
    0

Description

Currently the InteractiveShell (aka. groovysh) class is written in Java... and well, AFAICT there is no good reason for that. So re-write it in Groovy

Activity

Hide
Guillaume Laforge added a comment -

Requirements:

  • make sure we don't have to type 'go' anymore
  • allow class definitions not to be forgotten after execution of a valid script, so that we can further create instances of that class in the following valid scripts being executed
  • allow methods to be remembered as well and be available to the following valid scripts that will be executed (for instance, inspecting the script, finding new methods defined on it, and storing them as MethodClosures in the global binding, so that they are available for the next run)
Show
Guillaume Laforge added a comment - Requirements:
  • make sure we don't have to type 'go' anymore
  • allow class definitions not to be forgotten after execution of a valid script, so that we can further create instances of that class in the following valid scripts being executed
  • allow methods to be remembered as well and be available to the following valid scripts that will be executed (for instance, inspecting the script, finding new methods defined on it, and storing them as MethodClosures in the global binding, so that they are available for the next run)
Hide
Jason Dillon added a comment -

Any hints on how to get the underlying GroovyShell instance to remember things? Seems like it doesn't do that at all right now. Perhaps the SourceUnit needs to be inspected and then use that information to pull out bits from the compiled script... er something?

Show
Jason Dillon added a comment - Any hints on how to get the underlying GroovyShell instance to remember things? Seems like it doesn't do that at all right now. Perhaps the SourceUnit needs to be inspected and then use that information to pull out bits from the compiled script... er something?
Hide
Guillaume Laforge added a comment -

As you'll evaluate new scripts with GroovyShell, you can pass a binding containing variables. So in this binding, you can put MethodClosures wrapping methods defined in previous scripts.

Show
Guillaume Laforge added a comment - As you'll evaluate new scripts with GroovyShell, you can pass a binding containing variables. So in this binding, you can put MethodClosures wrapping methods defined in previous scripts.
Hide
Jason Dillon added a comment -

Okay, and I'm guessing that previously defined classes should already stick na?

What about things like:

def foo = "bar"

And more so... how does one figure out what methods (and or simple defs like above) were defined? Seems that the binding does not capture those (unfortunately IMO), so I'm probably going to have to use the SourceUnit to track those down?

Show
Jason Dillon added a comment - Okay, and I'm guessing that previously defined classes should already stick na? What about things like:
def foo = "bar"
And more so... how does one figure out what methods (and or simple defs like above) were defined? Seems that the binding does not capture those (unfortunately IMO), so I'm probably going to have to use the SourceUnit to track those down?
Hide
Guillaume Laforge added a comment - - edited
def foo = "bar"

is a local variable, so we won't be able to capture it and put into the binding, but:

foo = "bar"

will go in the binding of the script by default.

For methods, as if you evaluate this script:

def err(msg) { System.err.println(msg) }

you will have to introspect the Script class that is compiled to retrieve the methods that have been defined on it. Then, you wrap that in a MethodClosure that you keep inside the binding as 'err' (for the key), and the method closure for the value, so that later on, people can call err('hi') (in fact, the script will retrieve the err property in the binding, and as it's a closure, will call it)

The trickier thing is probably how to memorize the imports :-/
An idea could be to "catch" the imports as if they were shell commands, then you keep them somewhere in memory.
You could append them to the script evaluated, but you'd loose the right line number information.
So a better approach, ideally, would be to use the GroovyClassLoader and add imports transparentely when the script is compiled.
See blackdrag's blog for some ideas: http://blackdragsview.blogspot.com/2006/11/chitchat-with-groovy-compiler.html
This is also a technique that Alexandru Popescu used to add TestNG imports automatically in his Test'N'Groove project:
Look at the end of this file to see how to do that:
http://testngroove.googlecode.com/svn/trunk/src/main/org/codehaus/groovy/testng/GroovyTestNG.java

The last thing also that would be needed would be to remember class definitions, so that you can define a class in a first script:

class A {}

and then in another script execution being able to create new instances:

new A()

There might be some tricks with classloaders to make that possible though, and I'm not sure yet how to best do that.
Perhaps Jochen can give some perspective on this.

Show
Guillaume Laforge added a comment - - edited
def foo = "bar"
is a local variable, so we won't be able to capture it and put into the binding, but:
foo = "bar"
will go in the binding of the script by default. For methods, as if you evaluate this script:
def err(msg) { System.err.println(msg) }
you will have to introspect the Script class that is compiled to retrieve the methods that have been defined on it. Then, you wrap that in a MethodClosure that you keep inside the binding as 'err' (for the key), and the method closure for the value, so that later on, people can call err('hi') (in fact, the script will retrieve the err property in the binding, and as it's a closure, will call it) The trickier thing is probably how to memorize the imports :-/ An idea could be to "catch" the imports as if they were shell commands, then you keep them somewhere in memory. You could append them to the script evaluated, but you'd loose the right line number information. So a better approach, ideally, would be to use the GroovyClassLoader and add imports transparentely when the script is compiled. See blackdrag's blog for some ideas: http://blackdragsview.blogspot.com/2006/11/chitchat-with-groovy-compiler.html This is also a technique that Alexandru Popescu used to add TestNG imports automatically in his Test'N'Groove project: Look at the end of this file to see how to do that: http://testngroove.googlecode.com/svn/trunk/src/main/org/codehaus/groovy/testng/GroovyTestNG.java The last thing also that would be needed would be to remember class definitions, so that you can define a class in a first script:
class A {}
and then in another script execution being able to create new instances:
new A()
There might be some tricks with classloaders to make that possible though, and I'm not sure yet how to best do that. Perhaps Jochen can give some perspective on this.
Hide
Jason Dillon added a comment -

This is done, enable with NEWSHELL=t ./bin/groovysh atm.

Show
Jason Dillon added a comment - This is done, enable with NEWSHELL=t ./bin/groovysh atm.

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated:
    Resolved: