groovy
  1. groovy
  2. GROOVY-2053

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

          • Assignee:
            Jason Dillon
            Reporter:
            Jason Dillon
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: