The Artima Developer Community
Sponsored Link

Weblogs Forum
Creating an Interactive JRuby Console for the Eclipse Environment

10 replies on 1 page. Most recent reply: Oct 1, 2011 1:19 PM by Edward Garson

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 10 replies on 1 page
Jeremy Meyer

Posts: 40
Nickname: jeremy1
Registered: Jan, 2008

Creating an Interactive JRuby Console for the Eclipse Environment (View in Weblogs)
Posted: Apr 4, 2008 5:48 PM
Reply to this message Reply
Summary
Excited by the possibilities afforded by JRuby and the ability to plug it into various different Java environments, I decided to try implementing a JRuby interactive console in Eclipse.
Advertisement

Plugging in JRuby

Like so many others my imagination has been captured by Ruby. Perhaps it is because of the steep rise in its awareness the software development community has undergone since Rails, perhaps it is a combination of its quirky constructs, enthusiastic (and often surreal) proponents, and the fact that DSLs are gaining respect and momentum. At the same time, the JVM is becoming an obvious platform choice and Java itself is starting to look a little tired and lost as a language.

Perhaps Java is reaching its sell-by date, after all, there do seem to be natural universal laws about these things; and they apply to a great many domains. Fashion, empires and programming languages are three that I can think of which adhere to these rules. They rise, dominate and fall. Sometimes they come back, (like flared trousers and interpreters) but even if they die, they always leave their legacy, like the Roman Empire, or Cobol.

Anyway, it is obvious that however long it stays in vogue, one such mark that will be left by Java is the JVM as a platform, and fascinated as I am by Ruby, I think that JRuby is (together with Rails) what will really keep it on the map. I find myself more and more regularly explaining to colleagues and clients (partly to prevent them rolling their eyes as one does when faced with a religious fanatic, or a pushy salesperson) that I only really love Ruby and crowbar it into every discussion I can, because compiled languages like Java exist. JRuby makes using Ruby sensible (and cool).

Why is this cool? Because like so many consultants, it is my job it is to help people come up with general, repeatable solutions to their problems, so I am always on the lookout for some sort of lazy reuse idea. Since all clients want those three very simple and clearly mutually exclusive features that constantly haunt us, i.e. good, fast and cheap, I find myself drawn to the model of leveraging powerful application libraries with glue code or something minimal, scriptable and clever. JRuby fits that bill quite nicely.

No Silver Bullet

I wouldn’t propose anything as a silver bullet, but I have seen so many projects fail for the same reasons, that I am tempted by anything that can cut out some of the badness.

This means doing all sorts of things, ranging from trying to improve communication of requirements down to proposing better techniques of project management (so agile methodologies are always a popular choice). But anything that helps to cut out as many middle-men as possible, and allows the people with more domain knowledge to get closer to the engineering of the solutions has to be a good thing.

Or does it? Isn’t this falling into the old trap of trying getting non-programmers to write programs? Haven’t previous attempts at this failed? Languages like BPEL and Visual Basic and even (looking back a bit further) Cobol have all, in their own way, in their own domains tried to make programming easy. These have all ended up producing horrible languages. In the case of the latter two they have also produced code bases huge and prevalent by virtue of their easy proliferation, not their suitability for solving the problem. Not popular with OO purists and lovers of aesthetically pleasing languages!

Well now we have more languages like JRuby(and Jython and Groovy etc.) which allow us pleasing constructs, great power and efficient syntax together with access to Java libraries and access to any platform which has a JVM implementation. More importantly, perhaps, is that this translates into access to any Java middleware. Excellent! This means that the powerful application stuff can be written by the software engineers and the business logic can be written (at least initially) by the domain experts, using a domain specific language (or domain specific flavour, if language isn't subtle enough). This should mean that we can give an expert in the domain of feet enough power to shoot themselves in the foot with a homing missile, and they wouldn't have to be a rocket scientist.

What is doubly pleasing of course, is the fact that Ruby by its nature is dynamic (as are some of the other languages which have JVM implementations), and building a domain specific language to solve a problem can be implemented quite elegantly. So helping prevent our domain experts from getting in too much trouble is a bit easier. We can expose the important bits to them and shield the complexity from them. Very importantly though, they will always have the full power of the language at their finger tips should they need it.

Triply pleasing perhaps, is the fact that you can do all of this in an interactive shell (jirb in JRuby) if you want to, which is a great and agile way to wire up existing domain libraries, or produce "glue code". You can embark on a learning adventure with a framework, or library and produce a solution that can form the basis of something permanent. For example, you can experiment with the creation of swing applications using JRuby from the interactive shell. This is so easy that even a sock puppet could do it (and did, see here!).

Scripting in an Eclipse Environment

I got to thinking that one of the environments it would be great to play with was the Eclipse environment. It is a mature, fairly solid platform, with a sound plugin model and some very powerful development tools available in it. What would be great, I thought, would be if you could script in it, or create macros, even. Creating an interactive shell would give you access to any plugins you liked. Certainly it seemed it would be a worthwhile effort plugging in an interactive shell to see what would happen. As a self-confessed non-expert-but-fascinated wannabe Ruby-ist, I thought I could kill two birds with one (precious) stone, i.e. learn more about the language and learn more about the Eclipse platform at the same time.

How did I do this? Some of the highlights follow below. If you really can’t bear the thought of looking through code, or want to see everything in its entirety, then download this zip which has the Eclipse plugin and the full source included:

The obvious place to start looking at how to do this was jirb, the interactive Ruby shell written for JRuby. Of course, I thought, this would be a Java console that read in a line of text and passed it to the Ruby interpreter for evaluation, so it couldn’t be too hard to re-implement this in an Eclipse app.


Turns out I was slightly wrong. The jirb command, it seems, is just a batch file that runs JRuby and points it to irb. So irb, the interactive Ruby shell, is just a Ruby program and jirb , the interactive JRuby shell is just irb running in JRuby.

The Ruby Code

After some head scratching, I realised that this was very cunning and would actually help make my life easier. I did some investigation into the irb code, and with help from a good (albeit old) article by Leonard Richardson about unit testing the Ruby Cookbook source code, I discovered that redirecting irb input and output is fairly straightforward. Turns out that all you need to do is extend the Ruby Irb class and get it to use our own input and output streams. The Irb class implements the strategy pattern to read from its input stream using an InputMethod. Creating an Input Method is as simple as providing a Ruby class which has a gets operation and a prompt= setter method. The prompt= setter method is necessary, because irb will throw exceptions without it, (although I admit I am stumped as to why it is there, it doesn’t seem to do anything other than pass in an empty string.)

I needed to customise my prompt, and get the line of text typed, so:

class EclipseConsoleInputMethod
  # echo the prompt and get a line of input.
  def gets
	$stdout.print 'eIrb:> '
	$stdin.gets
  end

  def prompt=(x)
  end
end

And now, I could minimally extend the Ruby Irb class to give me a custom Irb class, which has the right context and some useful configurations:

class EclipseConsoleIrb < IRB::Irb

  def initialize(ec_inputmethod)
    IRB.setup(__FILE__)
    IRB.conf[:VERBOSE] = false
    super(nil, ec_inputmethod)
  end

  def run
    IRB.conf[:MAIN_CONTEXT] = self.context
    eval_input
  end
end

Not too hard at all! Now what I needed to do was get an Eclipse console to provide said input and output streams and pass the typed Ruby code into the former and echo the results into the latter.

The Java Code

Eclipse’s IO Console does that job very well, it displays in the normal Eclipse Console area, provides and input stream for you, and can have multiple output streams directed to it, perfect. (You can even set colours for the different streams!)

I created a simple Eclipse Plugin application using the basic Eclipse "new project" wizard. All I had to do was create a subclass of an IOConsole that had an instance of the RubyInterpreter class in it ..

Highlights below:

import org.jruby.Ruby;

public class RubyConsole  extends IOConsole implements Runnable {

   public void run() {
      ..
      RubyInstanceConfig conf = new RubyInstanceConfig() {
         public InputStream getInput() {return in;}
         public PrintStream getOutput() {return out;}
         public PrintStream getError() {return err;}
         ..
      }
      ..
      try {
         Ruby rubyRuntime = Ruby.newInstance(conf);
         String jRubyHome = System.getProperty("jruby.home");
         String jRubyVersion = System.getProperty("jruby.version");
         rubyRuntime.evalScriptlet("$:.insert(0,"+jRubyHome+"\\lib\\ruby\\"+jRubyVersion+"')");
         rubyRuntime.evalScriptlet("$:.insert(0,'"+jRubyHome+"\\lib')");
         rubyRuntime.evalScriptlet("require 'jruby';");
         rubyRuntime.evalScriptlet("require 'eclipse_console_irb';");
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

I got the input output and error streams from the superclass IOConsole, and used them to create an inner config class of type RubyInstanceConfig. I then used that to make the Ruby Interpreter. You will notice that once I create the new interpreter I call the evalScriptlet method with some Ruby script code. First I add the paths to the Ruby load path by inserting into the special Ruby array $: . I then issue two require statements. One to start JRuby and one to load up my Eclipse console Ruby script, which contains the Ruby code already shown above.

The Console can be added to the GUI by a very simple piece of code. I chose to add it by creating an action that creates a new Console, so I have a new menu entitled Ruby Console

Highlights below:

..
static RubyConsole ruby = new RubyConsole();
..
ConsolePlugin.getDefault().
   getConsoleManager().addConsoles(new IConsole[]{ ruby });
ConsolePlugin.getDefault().getConsoleManager().showConsoleView(ruby);
..
And that is it. There really wasn’t much more to it than that, so when I say highlights I actually mean almost everything. Most of what I have left out is the Eclipse plugin library code. All the Ruby code I needed is shown above.

After I build the plugin from my project, and deploy it, I get the rather pleasing result of a Ruby console in my Eclipse workbench with a eIrb>: prompt at the console, and the interpreter’s results shown as I type in commands. It even has nice colours. Shown here:


The Result

What can you do with this though? Well anything you like (within reason) but provided your plugin has added upstream plugins to its dependency list, you can load any Java classes you like from that plugin and work with them. For example, I have added the “org.eclipse.core.resources” to my RubyConsole plugin’s dependency list, and so I can access the Eclipse Workspace by typing:

eIrb:> include_class 'org.eclipse.core.resources.ResourcesPlugin'

irb responds with:
=> ["org.eclipse.core.resources.ResourcesPlugin"]

Indicating that I have loaded up the class..
eIrb:> workspace = ResourcesPlugin.get_workspace

Yields:
=> #<Java::OrgEclipseCoreInternalResources::Workspace:0x25abb1 @java_object=org.eclipse.core.internal.resources.Workspace@12605d>
So I now have the workspace object stored in workspace. The great thing about this environment of course, is that should I feel I can’t be bothered to look in the Javadocs for the methods available on the Eclipse Workspace class, I can make use of Ruby’s reflection by just typing:
eIrb:> workspace.methods

Which returns a huge array of all the methods (too big to list here). I can then experiment with the sensible looking ones, and soon discover that:
eIrb:> projects = workspace.get_root.get_projects
eIrb:> projects.each { |p|
eIrb:> 	puts p.get_name
eIrb:> }

..will list all of the names of the projects in my Eclipse workspace, while:
eIrb:> projects[0].build(0,nil)

..will force the first project in the workspace to build.
eIrb:> projects[0].close(0,nil)

..will close the project, while:
eIrb:> workspace.get_root.get_project('project1').open nil
.. would open a project in my workspace called ‘project1’. Of course this is not good coding style at all, and if you didn’t have a project with this name, you would get a Java exception reported at the Ruby prompt, but you get the idea. All in all, this is a really agile way to develop and a great way to test and experiment with libraries and middleware. Of course, once you have a piece of Ruby code that does something useful, you can save it in a .rb file and use the Ruby’s require statement at the prompt to load it up. You would then be able to continue typing interactively.
eIrb:> require 'useful.rb'
I hope you have fun playing around with this. Enjoy!

Resources

The plugin with sourcecode. All version info, etc. in the readme.txt:
RubyConsoleJeremyMeyerBlog.zip

Puppets Do JRuby:
http://www.artima.com/weblogs/viewpost.jsp?thread=220459


Werner Schuster

Posts: 8
Nickname: murphee
Registered: Mar, 2006

Re: Creating an Interactive JRuby Console for the Eclipse Environment Posted: Apr 5, 2008 4:11 PM
Reply to this message Reply
... or you might just use EclipseShell:
http://eclipse-shell.sourceforge.net/


BTW: you don't have to include plugins explicitly to get access to their classes - look up "Buddy-Classloading" for OSGi and that'll do the trick, ie. you'll have the whole Eclipse world at your hand.

Jeremy Meyer

Posts: 40
Nickname: jeremy1
Registered: Jan, 2008

Re: Creating an Interactive JRuby Console for the Eclipse Environment Posted: Apr 9, 2008 1:06 PM
Reply to this message Reply
So that is a really nice looking tool, and I like your instructional videos, well done. One thing I find confusing, though, is your console output. You have a text editor for the Ruby code, but the output goes to a console. You also state that actual Ruby output goes to the Eclipse stdout, and not to the console. So, a statement like "puts 'result is ' + jrubyClass.get_result" will go nowhere unless you have run Eclipse with the DOS prompt showing. By splitting up the input / output, you don't really have an interactive shell because there is no visible order of command vs output. For my little exemplar I just extended JIRB because it gave me all that with 12 lines of Ruby code! (although it is a primitive shell, with no history etc.)

Still, it seems to be a great general purpose tool for scripting in Eclipse and I would certainly consider using it myself. Thanks for the tip about OSGi.

Werner Schuster

Posts: 8
Nickname: murphee
Registered: Mar, 2006

Re: Creating an Interactive JRuby Console for the Eclipse Environment Posted: Apr 9, 2008 8:25 PM
Reply to this message Reply
> So that is a really nice looking tool, and I like your
> instructional videos, well done. One thing I find
> confusing, though, is your console output. You have a text
> editor for the Ruby code, but the output goes to a
> console.

Yep - take a gander at Squeak (or other Smalltalk implementations):
http://www.squeak.org/
EclipseShell's editor is like Squeak's/Smalltalk's Workspace (not to be confused with Eclipse's Workspaces). In Smalltalk, a Workspace is basically a Shell to execute code. They also don't show the results inline, but instead you show output in the Transcript (Smalltalk's version of the Console View).
Another reason is to be able to have concurrent output from a script; ie. if you run a long running script, it can continue to dump stuff to the console. That would not be possible if all output went to the editor, because:
a) it'd be horribly annoying if you're typing the next line, and the editor would keep jumping about due to insertion (there might be something to be done about that, but I'm not interested in finding out).
b) in EclipseShell, you can close the editor and keep the JRuby instance running in the background (a la Unix job management).



> You also state that actual Ruby output goes to
> the Eclipse stdout, and not to the console.

Yeah... the JRuby version shipped with the version that's online right now is ancient and didn't have a way to re-route stderr/stdout (believe me... I tried).
I'm going to release a new version that ships with JRuby 1.1, probably in a week or so, which does the right thing.
This works with the Beanshell and (I think) Rhino support in EclipseShell because they already allowed this stderr/stdout re-routing.

Jeremy Meyer

Posts: 40
Nickname: jeremy1
Registered: Jan, 2008

Re: Creating an Interactive JRuby Console for the Eclipse Environment Posted: Apr 10, 2008 5:12 AM
Reply to this message Reply
> Yeah... the JRuby version shipped with the version that's
> online right now is ancient and didn't have a way to
> re-route stderr/stdout (believe me... I tried).

Actually, I think even with the version I used there was some strange funk there. I set JRuby's output stream using an instance of RubyInstanceConfiguration class, but when I first ran it I had to use rubyRuntime.defineGlobalConstant( etc.) and set Ruby's $stdout to the output stream from the Eclipse Console. For some inexplicable reason, when refactoring later I took this out and it worked fine.

Lastest version of JRuby is just released, so we might both get some joy from that :)

James Ervin

Posts: 1
Nickname: jervin
Registered: Jan, 2008

Re: Creating an Interactive JRuby Console for the Eclipse Environment Posted: Apr 11, 2008 3:07 AM
Reply to this message Reply
This article has inspired me to attempt to add a console to my groovy monkey tool http://groovy.codehaus.org/Groovy+Monkey .

In groovy monkey at the moment you can write scripts in beanshell, groovy or ruby. I am hoping to add in Jython soon.

There is already the notion of associating a metadata header with a given script, you know having that ability to associate the header metadata with a shell would be extremely powerful in Eclipse. The header metadata stored in some manner, would allow a user to add different bundles to the classloader, jars in the workspace or class folders in the workspace. Adding the metadata to a console might be mighty powerful. Talk about API exploration, wow.

Perhaps in addition to the metadata, could even add in a function to allow the user to select sections of the session (or the whole thing) and use them to spawn a more permanent script. Wow this could have some possibilities. :)

Thanks for the article.

Jeremy Meyer

Posts: 40
Nickname: jeremy1
Registered: Jan, 2008

Re: Creating an Interactive JRuby Console for the Eclipse Environment Posted: Apr 13, 2008 6:33 PM
Reply to this message Reply
Another excellent tool! Great to have been any kind of inspiration at all. Metadata headers are an interesting idea. A puzzling one too, because there is almost an elegance to keeping true to the original language, and adding nothing that it can't do. e.g. using the Ruby 'require' statement extends the basic console to do almost anything (even strange things like pop up a Java Swing library from an Eclipse app). This also means that you could write any meta functionality as accompanying Ruby scripts (in your case, Groovy or whatever language you like).

But.. why not generalise that into a meta-scripting environment, even? Could be great!

Craig Taverner

Posts: 1
Nickname: craigtav
Registered: Oct, 2008

Re: Creating an Interactive JRuby Console for the Eclipse Environment Posted: Oct 10, 2008 8:35 AM
Reply to this message Reply
This was a very informative and useful post, but I was unable to get it to work on any version of JRuby newer than the one you used (I tried everything from 1.1RC1 through 1.1.4). The second user input to the IRB would always throw an exception on the input stream being closed unexpectedly. I wonder if this is in any way related to the comments by Werner regarding changes in the stdio between versions?

Anyway, due to this, and some other factors related to plugin dependencies, I took another path, and wrote a plugin that creates a simple view that embeds the jirb_swing console shipped with JRuby. That console is available in the org.jruby.demo.IRBConsole class and can be wrapped in a simple SWT composite using SWT-AWT bridging.

Overall, I think my code was as simple as yours, and achieved an embedded IRB that is much more like the standard one, with the same irb-prompt look and feel and behaviour. Of course, architecturally it is perhaps not as nice, since I use SWT to wrap AWT containing Swing code, but it works fine, so I'm happy.

I've since split my plugin into two, a simple generic one with minimal dependencies, and an application specific extension for my work (which, for example, pre-runs a number of startup ruby scripts before the IRB, so I can have a DSL in the IRB). I am happy to publish the generic part (including example usage), as open source should anyone be interested. Even the specific part is earmarked for open source, but a bit later I think.

Gabor Kulcsar

Posts: 1
Nickname: egbokul
Registered: Dec, 2008

Re: Creating an Interactive JRuby Console for the Eclipse Environment Posted: Dec 23, 2008 6:43 AM
Reply to this message Reply
Found this thread via Google after I'd spent a large amount of time looking for a (J)Ruby shell working on the Eclipse platform. Believe or not, I couldn't find one, but this was the solution that looked to be the most promising. At least it had worked (once upon a time), and the error message (stream closed) looked like there's something fundamentally wrong, which can sometimes be surprisingly easy to fix. And after a short(?) debugging session I found the reason: org.eclipse.ui.console.IOConsoleInputStream has an incorrect implementation of the available() method. Let's have a look at it:
    public int available() throws IOException {
        if (closed && eofSent) {
            throw new IOException("Input Stream Closed"); //$NON-NLS-1$
        } else if (size == 0) {
            if (!eofSent) {
                eofSent = true;
                return -1;
            } 
            throw new IOException("Input Stream Closed"); //$NON-NLS-1$
        }
        
        return size;
    }


OK, so what happens if someone calls available() when there are no bytes available in the stream? The first time it sets a flag, but the second time (and forever after) it throws an exception. WTF? Since we are talking about a console input stream what sense does it make to act like there can be no more input (from the keyboard)?
Now for some reason the Ruby IRB implementation calls available() twice for each input line, and of course the second call will set the flag and therefore make the stream unusable.
Fix: remove the eofSent flag (which is btw. not used anywhere else in the file) and voila, you've got an almost perfect IRB working in an Eclipse console!
The only problem now is the caret position, but that's just a minor annoyance compared to this issue.

The architecture of the console plugin is hopeless by the way, I couldn't find a way to fix this problem without recompiling the original plugin (which was another long suffering - but I'm new to the Eclipse world, so it may be my skills that are lacking here...). I couldn't subclass IOConsoleInputStream in a way that my own inputstream could work with my Console subclass - it is true that the documentation says the input stream is not intended to be subclassed - but why?
Now if only I could find out how to report this bug to IBM, or Eclipse.org, or whoever are responsible...

I'm getting more and more convinced that OOP is not the future - have you checked Clojure lately?

Nick Preiser

Posts: 1
Nickname: npreiser
Registered: May, 2010

Re: Creating an Interactive JRuby Console for the Eclipse Environment Posted: May 17, 2010 7:38 PM
Reply to this message Reply
I am trying to do the same thing you did using tcl.

I am using JACL as the back end and it is working
just fine, except that the cursor/carat postion
is wrong after each command.
The cursor ends up reverting back to the
beginning of the input line , rather then the
prompt that follows the output.

Do you or anyone have any idea how to set
/fix the carat position issues with the IOConsole?,

thanks,

Edward Garson

Posts: 1
Nickname: egarson
Registered: Jan, 2005

Re: Creating an Interactive JRuby Console for the Eclipse Environment Posted: Oct 1, 2011 1:19 PM
Reply to this message Reply
Thank you Jeremy: very helpful!

Flat View: This topic has 10 replies on 1 page
Topic: Scala: The Static Language that Feels Dynamic Previous Topic   Next Topic Topic: Speaking in Grenoble, France and Stockholm


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us