Martin's Blog

Friday Jun 13, 2008

JRuby Fast Debugger 0.10.1

Friday the 13th, the good time for a new release :), here it is:

News

  • Main feature or benefit is that all the new features of MRI's CLI fast debugger might now be utilized. See CHANGES and Changelog for ruby-debug 0.10.1 release and check Debugging with ruby-debug manual. Rocky Bernstein pushes the CLI interface to be compatible with, or similar to, the one used for gdb. So be sure to check the CHANGES or type 'help' command into debugger console to check the new commands or the ones whose behaviour have changed.
  • No -J-Djruby.reflection=true -J-Djruby.compile.mode=OFF monster is needed any more. JRuby 1.1.2 (see JIRA 2474 for details) comes with special flag for debugging. Now all is needed is to pass --debug parameter to JRuby. So to debug your application, you just need to run:
      jruby --debug -S rdebug <your-script>
      
  • ruby-debug-base since version 0.10.1 depends on other native gem - linecache. With jruby-debug-base this is not needed since we are workarounding this by dummy linecache fake directly in jruby-debug-base. This means that we are not as clever as C ruby-debug-base - particularly in JRuby debugger you might put breakpoint on lines with no executable code where C implementation would cleverly reject it. In future there will be hopefully decent implementation of linecache. Any volunteer? :)
  • we are now passing almost whole, little bit tweaked, test suite of MRI ruby-debug 0.1.10. Few patches were contributed to ruby-debug-base implementation independence (whether it is MRI, JRuby or Rubinius one). Thanks ruby-debug team for the great test suite. This helps stability and compatibility of all implementations.
  • following up from the above point several bugs were fixed.
  • see ChangeLog for details.

Good to know

Since there were some API changes in JRuby 1.1.2 the jruby-debug-base 0.10.1 release does not work with JRuby 1.1.1 and older, only with JRuby 1.1.2+.

Installation

For installation see debug-commons website or Using the JRuby Debugger on JRubyWiki.

Enjoy and any feedback is welcomed as always.

Wednesday May 07, 2008

Scripting NetBeans in Ruby

Few times we were asked whether is is possible to write NetBeans Ruby IDE extensions in Ruby. We usually replied not yet. But having:

  • NetBeans running on the JVM
  • JRuby on the same VM
  • JSR 223 which is part of JDK 6

there are no reasons why it should not be possible now.

So I've started to peek around what would be needed to provide convenient extension with which the Rubyists would be able to start to tweak NetBeans IDE in Ruby language only. I did not start exactly with such support, but instead started with kind of NetBeans Ruby IDE scripting support. I've recalled Jesse's idea for IDE scripted by JavaScript and applied similar to Ruby.

Working with NetBeans Ruby's dev builds and very often starting with clear userdir and still reopening my projects, I now have the following script instead which I simply run from CLI after fresh NetBeans starts up (just work from IRB as well):

      1 require 'nb_ext'
      2 netbeans = NBExt.find_first
      3 netbeans.attach
      4 netbeans.open_projects(
      5   '/space/java/netbeans-hg/main/ruby.debugger',
      6   '/space/java/netbeans-hg/main/ruby.platform',
      7   '/space/java/netbeans-hg/main/ruby.project'
      8 )

How does it work?

Below are some details of implementation with inlined snippets of code for convenience. Full code might be downloaded here, Java agent here.

(2) The script finds running NetBeans instance. The find_first methods goes through the currently running JVM instances and greps for the NetBeans and returns the first one (or nil). Thus if you are running more NetBeans instances use find_by_userdir or find_all instead.

      1 vm_desc = VirtualMachine.list.detect do |desc|
      2   desc.display_name =~ /org.netbeans.Main/i
      3 end

(3) attach to it via Attach API

      1 VirtualMachine.attach(@vm_desc)

(4) and opens given project(s) in the running NetBeans IDE. open_projects method just compose projects to be opened with the code utilizing NetBeans APIs (open_projects_code.rb) and sends it to the agent, running inside NetBeans process VM, for evaluation.

       1 def open_projects(*projects)
       2   code = "projects = ['#{projects.join("','")}']\n"
       3   code_file = File.join('code', 'open_projects_code.rb')
       4   code << File.read(code_file)
       5   eval_code(code)
       6 end
       7
       8 def eval_code(code)
       9   output = Tempfile.new('output')
      10   @vm.load_agent(@agent_jar, "#{output.path}#{File::PATH_SEPARATOR}#{code}")
      11   File.read(output.path)
      12 end

Template for opening projects is simple:

       1 include Java
       2
       3 import 'java.net.URI'
       4 import 'org.netbeans.api.project.FileOwnerQuery'
       5 import 'org.netbeans.api.project.ui.OpenProjects'
       6
       7 raise("projects must be defined") unless defined?(projects)
       8
       9 to_open = projects.map do |prj|
      10   uri = URI.new("file://#{prj}")
      11   FileOwnerQuery.get_owner(uri)
      12 end.compact
      13
      14 to_open_p = to_open.to_java('org.netbeans.api.project.Project')
      15 OpenProjects.getDefault().open(to_open_p, false)

Note that projects variable is defined in the open_projects method code composition. Likely templating mechanism would fit here.

Everything written in the Ruby language, just agent class is written in Java (with future JRuby compiler even this piece could be written in Ruby).

Just a playground so far…

This is really just an example how it might be done. Developing such extensions, or writing such scripts, is still little awkward and not that easy to test and one needs to know NetBeans APIs, but that's likely OK when wanting to write NetBeans extensions/scripts.
In the future we could bridge some basic NetBeans APIs to Ruby, like the artificial open_projects method above, to make it easy to write such scripts which adds e.g. new menu items. Also it should not be hard to write some support into NetBeans where you would manage your scripts and which will be automatically loaded when NetBeans starts up. Ideally there would be also some support for testing such script -> write in IDE, run/test it in IDE. Not that simple, but something like this.

It depends whether there is really such a request from NetBeans Ruby users and whether the effort spends on the support does worth it, whether the NetBeans users would like to script or extends NetBeans in Ruby and what would be such use-cases.

If you have any ideas how such support should look like or how does it look in other IDEs, Editors supporting Ruby extensions, let me know.

Can I try it?

Yes, you can. But it might not be that easy at the moment since we are facing issue with bundled tweaked JRuby. So firstly you might try to download and install this NetBeans module (4384kB!, contains jruby.jar) which should enable JRuby scripting in Netbeans. I've spent some time with this but still does not work. On the other hand my colleague Erno, does not have problems I'm encountering. So your mileage may vary.
If it throws strange JRuby internal exceptions, use second brute-force method, and just copy-paste jruby.jar from your JRuby distribution (lib/jruby.jar) and jruby-engine jar to your $JAVA_HOME/jre/lib/ext directory. Then start the NetBeans IDE and above should work. You will get some exceptions from our NetBeans Ruby lexer/parser if you used brute-force method, but for playing should be enough until we solve the issue appropriately.