Bryan Weber

All | General | Java | Ruby | JRuby | Groovy | Scala | Erlang | Scheme
XML
20080123 Wednesday January 23, 2008
No! Bad Groovy! Argh! Bad groovy! Bad groovy!
Groovy was designed to be tightly integrated with Java. JRuby was written to be an implementation of Ruby that runs on the JVM. But groovy has gone one step too far. It has incorporated one of Java's worst features! In Java, primitives do not throw exceptions for operations that are not within the range of the data type. That is to say, if you add 1 to Integer.MAX_VALUE you end up with Integer.MIN_VALUE! This is of course not only confusing but mathematically incorrect. This is the type of thing that should be taken care of at the programming language level in my humble opinion. So let's compare how Groovy and JRuby handle this simple calculation.
Program:
i = Integer.MAX_VALUE
j = i + 1
println j
println j.class

k = 12345678901234567890
l = k + 1
println l
println l.class
Output:
-2147483648 
class java.lang.Integer 
12345678901234567891 
class java.math.BigInteger
JRuby code:
require "java"

i = java.lang.Integer::MAX_VALUE
j = i + 1
puts j
puts j.class

k = 12345678901234567890
l = k + 1
puts l
puts l.class
JRuby output:
2147483648
Fixnum
12345678901234567891
Bignum
I like Groovy a lot because of its tight integration with Java, but this is something that Groovy missed big time. Breaking away from tight Java integration would have been perfectly fine in this case to provide results that any sane person would expect, ie the one that is mathematically correct.
Posted by bweber Jan 23 2008, 08:39:54 AM EST
20080109 Wednesday January 09, 2008
Creating data in groovy with builders

We often have the need to create data. We use data for integration tests, to populate database tables in production for releases, and many, many other reasons. This article talks about one way to get data into your database in a way should allow for it to be modified without too much trouble when those changes come your way in the not so distant future...

Is this even a good idea?

Something that occurred to be recently is that builders, as implemented in Groovy (or JRuby for that matter), might be a good way to create and manage test data for some Java unit tests. But I wasn't really sure, so I set out to determine if in fact it was a good idea or not. If you aren't familiar with builders, read Builders. For better information, read Manning's Groovy in Action. From now on, I will assume you are already familiar with builders. If you are too lazy to follow the links, builders lend themselves to displaying tree based data structures well because the code is in a form that visually represents the data structure. It does this by using some neat meta-programming tricks and closures. If you aren't familiar with meta-programming or closures you might want to read about them first as well. Wikipedia probably has better information on closures. [Wikipedia Closures]

What about XML?

In the past I have used xml to manage data for unit tests and in theory this means that Java objects or XSLT can be used to modify the data. However, in practice, while either is adequate for modifying test data, neither is particularly simple or elegant. Adding columns, modifying relationships, etc is typically not a trivial task when the data is in xml. Let's be honest (and I can't believe I'm about to put this in writing), for test data, I want to modify it in a Spreadsheet (Excel or Open Office's Spreadsheet or iWork Numbers). Why? Well, because adding and removing columns is simple, macros are supported, copy and paste is simple, etc. So why am I bringing this up? Well, how about because data in a builder (a tree) can be exported to csv with very little code, modified and imported back into the builder with minimal code. So why not store the data in csv format then? I cannot think of any compelling reasons not to as a matter of fact, especially if you were to use the same data for tests in different languages! But for now, I am keeping my data in groovy code, code that I believe is very readable. (To be fair, you could go from xml to csv and back again, but reading and manipulating xml is more difficult than reading the same data in the builder tree. I have included the code below that goes from a builder to csv and back. I challenge you to write code that does the same for xml. It might be possible, but I believe that most, if not all, people would have to write more code to achieve the same result. If you decide to keep your data in csv and not groovy then it might be a perfectly acceptable alternative to use xml, I'm not knocking it, I just think it can be done in a simpler way.)

Trees vs. Graphs

Your first thought might be, well data for unit tests is probably an object graph, not a tree! The data is most likely going to go into a RDBMS after all. While this is true that the data is a graph, it can be represented as a tree(s). A node in the tree can point to another node in the tree, not just one of its parent nodes. Think xml refs if you are having a tough time following the idea. The problem is that unlike xml refs there is no check to verify that the other end of the connection exists. Therefore, I suggest loading the data into a RDBMS and let it do what it is good at, enforcing the relational integrity. For testing, I suggest an in memory database like HSQL. As an aside, dividing the data into logical groups is also a good idea. (This can be done regardless of whether you use a tree or a graph.) It allows us to manage logical data sets independently. For example, I might have users and roles which are kept separate from office locations.

Referential Integrity

Pointers to data in other tree nodes are not referential so data integrity is not ensured. Again, you are probably thinking, it sounds like I am trying to convince you that builders are NOT appropriate for creating and managing test data, but wait... the database can do it and do it well. So why not let the db do that work for you? Since the data itself does not guarantee the referential integrity you do not get static analysis time protection. However, you can create unit tests that insert your data into an in memory data base and this will ensure that your data has its referential integrity. Assuming of course that you run your unit tests and that you have foreign key relationships!

Data Builders and Data Persisters

So, what does this code look like? We'll get to it shortly. But first, let's talk about what the "real" code will do? Well, there are 2 primary things for each set of data.

Data Builders

First, there is the data builder which is our tree of data. This is a groovy file that contains our actual data values. An example:
    def getData() {
        new NodeBuilder().users {
            user(user_id: "123", first_name: "Joe", last_name: "Smith") {
                address(address_type: "home", street: "123 Main St.", city: "Springfield", state: "MA", zip: "12345")
                address(address_type: "work", street: "456 South St.", city: "Boston", state: "MA", zip: "98765")
            }
            user(user_id: "456", first_name: "John", last_name: "Doe")
            user(user_id: "789", first_name: "Jane", last_name: "Doe")
        }
    }

Data Persisters

Then there is our persister, which in our case uses GPath (similar to XPath, but walks Groovy objects) to pull data out of the builder and persist it. In my case that means populating Hibernate objects and then saving the hibernate objects.
    def persist(tree) {
        tree.grep() { 
          User user = new User()
          user.userId = it.@user_id
          user.firstName = it.@first_name
          user.lastName = it.@last_name
          it.address.grep() { address ->
            Address addr = new Address()
            addr.addressType = address.@address_type
            addr.street = address.@street
            addr.city = address.@city
            addr.state = address.@state
            addr.zip = address.@zip
            user.addresses.add(addr)
          }
          userDao.save(user)
        }
    }

We separate these objects so that multiple data sets can be used depending on the environment or test suite. In other words, it is good to keep the data separate from the code that will manipulate the data.

The data

As an example, let's suppose we want to add some users to our database. Let's assume that there are 3 users and the first user has 2 addresses. The tree might look something like this in csv format:

users
,user,user_id,123,first_name,Joe,last_name,Smith
,,address,address_type,home,street,123 Main St.,city,Springfield,state,MA,zip,12345
,,address,address_type,work,street,456 South St.,city,Boston,state,MA,zip,98765
,user,user_id,456,first_name,John,last_name,Doe
,user,user_id,789,first_name,Jane,last_name,Doe
What might this data look like in xml?
  <users>
    <user user_id="123" first_name="Joe" last_name="Smith">
      <address address_type="home" street="123 Main St." city="Springfield" state="MA" zip="12345" />
      <address address_type="work" street="456 South St." city="Boston" state="MA" zip="98765" />
    </user>
    <user user_id="456" first_name="John" last_name="Doe" />
    <user user_id="789" first_name="Jane" last_name="Doe" />
  </users>
And in groovy?
users {
  user(user_id:"123",first_name:"Joe",last_name:"Smith") {
    address(address_type:"home",street:"123 Main St.",city:"Springfield",state:"MA",zip:"12345") 
    address(address_type:"work",street:"456 South St.",city:"Boston",state:"MA",zip:"98765")
  }
  user(user_id:"456",first_name:"John",last_name:"Doe")
  user(user_id:"789",first_name:"Jane",last_name:"Doe")
}

Which do you find to be the most readable? Some will say xml, most will say groovy. But more importantly, the impedance is zero for groovy because it is already groovy code and no transformation is necessary. Whereas, if we have xml some transformation is necessary.

Let's suppose that we also have a Role table for security
roles
,role,role_type,admin,description,System Administrator
,role,role_type,data_entry,description,Data Entry
What if we wanted to have a reference from a user to a role or vice versa? Imagine something like this snippet:
user,user_id,123,first_name,Joe,last_name,Smith
,role,admin
,role,data_entry

Getting back to an earlier point, seeing this should probably scare you a little. The string (think symbol if you like ruby or atom if you like many other programming languages) 'data_entry' is entered in two places so if it is modified in one place our structure breaks down. Well, with foreign key constraints in your db this should be solved for MOST (but not all) cases.

Isn't it about time for some code?

Code to convert a Builder to csv:

    def print_csv(node,indent) {
        def result = ""
        result += "," * indent
        result += "${node.name()},"
        node.attributes().each { attribute ->
            result += "${attribute.key},${attribute.value},"
        }
        result += "\n"

        node.grep() { child ->
            result += print_csv(child,indent+1)
        }
        result
    }

Code to convert csv to a Builder:

    def static read_csv(str) {
        def lasts = []
        def root
        str.split('\n').each {line ->
           def arr = line.split(',')
           def depth = 0
           // determine depth
           while ( arr[0] == "" ) {
               arr = arr[1..<arr.size()]
               depth++
           }
           // determine parent node
           def parent
           if ( depth == 0 )
             parent = null
           else
             parent = lasts[depth -1]
           // create new node
           Node node = new Node(parent,arr[0])
           // is this our root?
           if ( lasts.isEmpty() ) {
               root = node
           }
           lasts[depth] = node
           // process attributes
           def key = null
           arr[1..<arr.size()].each {
               if ( key == null ) {
                   key = it
               }
               else {
                   node.attributes().put(key,it)
                   key = null
               }
           }
        }
        root
    }    

Conclusion

So is keeping data in this format for unit tests a good idea or not? That's for you to decide!

Footnote

PS After writing this code, I became aware of the ObjectGraphBuilder in Groovy, which allows for relationships between nodes in the tree, but only to parent nodes. Since we are interested in relationships to nodes in other branches or other trees I haven't seen a compelling reason to switch to the other Builder implementation yet.

Posted by bweber Jan 09 2008, 10:24:53 PM EST
20071105 Monday November 05, 2007
RubyConf 2007 Day 3 Highlights of day 3 for me:
  • Adhearsion
  • RSpec
  • Solr
  • Metasploit
Adhearsion

VOIP library built on top of Asterisk (which sounds awful to have to use). Demos were cool. Test coverage was ... low to put it mildly. :)

RSpec

RSpec unit testing is fine, demo of ping pong development was simple, but the merge of another test framework (Fit I think? I can't recall for sure.) into the soon to be released RSpec version was simply awesome. Hats off to the team for getting me interested in testing again for the first time in quite some while. Basically, they've designed a DSL for BDD and a really cool looking UI. I've read a fair bit before on BDD but never really saw what distinguished it from TDD to make me investigate it further. I'm actually looking forward to the new version of RSpec being released now so I can start testing RSpec BDD style. There are 3 ways that the new framework can be used: pure ruby, dsl and I forget... (probably some variation of the first 2). The dsl version basically split the description part into a dsl (in theory to be used by "business users", which would almost never happen in practice) and the implementation part was still in ruby. Ryan D. had a problem with the dsl version because it was too far away from ruby syntax, but no one in the crowd backed him up. In fact, I think it is a positive. I'd like to see JBehave and other BDD frameworks adopt the dsl so that tests could be written for any scenarios regardless of the implementation language!

Solr

So its been a little while since I last used Lucene, but I really liked this presentation and I thought it was one of the most relevant talks. Solr basically exposes search via http. I have some questions about using solr for federated searches which I'll be investigating further myself, but I'm sure that a significant percentage of projects have the need for something at least similar to solr.

Metasploit

OK, I've seen metasploit before, but its been ported from perl to ruby (the part of it that was in perl anyway)... so now its assembly, c and ruby. And let's just say that attaching irb to running processes on remote boxes is way too easy and way cool.

Honorable mention

Justin's talk on identity (OpenID and CAS) was very practical and useful and rubigen might come in handy some day, but the presentation had too much video and not enough let's roll up our sleeves and write some code examples.
Posted by bweber Nov 05 2007, 10:58:26 PM EST
20071103 Saturday November 03, 2007
RubyConf 2007 Day 2 Highlights of day 2 for me:
  • IronRuby, JRuby and Rubinius
  • Mac OS X Loves Ruby
  • Matz Keynote

MRI (CRI) vs. IronRuby vs. JRuby vs. Rubinius vs. YARV

IronRuby, JRuby and Rubinius presentations opened the day. Nothing too new here. IronRuby is the port of Ruby to .NET. It has the farthest to go. JRuby is pretty far along. Rubinius contends that ports shouldn't be to .NET or the JVM, but to ruby itself, at least for as much of the runtime and kernel (read standard libraries) as possible. IMHO this would make the jobs of the IronRuby and JRuby teams much easier, but unfortuantely, Rubinius is not complete so they cannot build on top of Rubinius. YARV is the much anticipated Ruby 1.9 virtual machine that promises significant performance improvements, but it wasn't really discussed in detail at this point.

Mac OS X Loves Ruby

Focused on Leopard. In particular focused on RubyCocoa and DTRACE. The RubyCocoa examples were visually cool. One used Ruby to open a GUI and make it read a message out loud. XCode was used as the ruby editor, which it appears Apple is trying to coerce developers into using. The GUI was built using drag and drop in XCode and the ruby code was tied to GUI components by clicking and dragging in XCode. Another example used a script to attach ruby to a running process (TextEdit) and manipulate the process (resize, change window name, change editor text) real time in irb. This example was particularly interesting and grabbed my attention from a security standpoint. While this stuff was cool, I don't write software only for OS X so I won't be touching any of it. DTRACE is for debugging operating system calls by applications and it is included with Ruby on Leopard.

Matz Keynote

Focused mainly on Ruby 1.9 and 2.0 features. 1.9 is a transitional release that breaks compatibility with 1.8.6 syntax. Ruby 1.9 will be released before the holiday season, ie end of 2007, but it seems like it might be a historical footnote. In fact, Ruby 1.8.6 will still be the production stable release. Ruby 1.9 will switch from green threads to operating system threads. 1.9 introduces (somewhat controversially) parameters after optional parameters. Matz cleared up the air by stating that this was a transitional stage on the way to named parameters which will be added at some point in the future.

Oh, and everyone in attendance is aware that tonight is daylight savings time.
Posted by bweber Nov 03 2007, 08:43:25 PM EST
20071102 Friday November 02, 2007
RubyConf 2007 Day 1 Day 1 of RubyConf 2007 is complete. Highlights of the day for me were:
  • Jim Weirich's presentation on Advanced Ruby Class Design
  • Nathan Sobo's presentation on Treetop
  • Ryan Davis' presentation on Hurting Code for Fun and Profit

Advanced Ruby Class Design

Well done presentation specifically tailored to developers coming from Java or C#. Included examples from some of the most mature ruby libraries around. Jim wanted to present examples that were fun and interesting and he delivered.

Treetop

I had to choose between this presentation and ropes. I'd still like to learn more about ropes someday, but I'm really glad I went to this presentation. Treetop isn't for everyeone, but I love the ideas behind Treetop and I can't wait until it is slightly more mature (and [better] documented). I've already downloaded the gem (and facets as it is required) and played with Treetop a little. My first impression is that it does not work in JRuby 1.0.1 at all which is unfortunate. I'm not sure if this is a JRuby bug, a problem with something in facets or a problem with Treetop itself. UPDATE Recently released JRuby version 1.1b1 fixes the problem so it was a JRuby bug. Hopefully Treetop will be replacing Gold Parser Builder and antlr in my mythical developers toolbox soon. This project embodies the ruby community for me, it is approaching a very old problem in a very new way (admittedly Nathan isn't the idea originator, but who is doing parsing this way in the Java/.NET world?) and a very ruby way.

Hurting Code for Fun and Profit

A non-technical presentation, but very entertaining and relevant presentation nonetheless. I almost passed on this presentation because I thought the presentation was oddly named and the extract contained words like "ascetic" which I did not know the meaning of. And the reference to "for fund and profit" ("Smashing the stack for fun and profit" being the reference, at least, that's the first reference to "for fun and profit" that I'm aware of) didn't really seem to make sense either. So what exactly is hurting code? Well, it turns out that it is hurting (refactoring/re-writing/modifying) code that you do not like instead of hurting the offending developer(s). Code that "you do not like" is very open to interpretation and Ryan basically defined it as code that doesn't sit well with you (instinctual) as opposed to some concise algorithmic approach. The presentation did mention a couple of tools (all developed by Ryan I believe) that could potentially help detect code that probably should not sit well with you, but they were not really the focus of the presentation.

Looking forward to day 2!
Posted by bweber Nov 02 2007, 08:49:41 PM EST
20071023 Tuesday October 23, 2007
Writing testable Java code with stateless collaborators Writing testable Java code is an often discussed topic that has been covered ad nauseam. So what could another blog post possibly contribute? Well, I've been following a simple pattern recently and it makes for some very simple, clean (imho) and testable code. I never call a method that resides within the calling class. Ok, so maybe never is too strong, but every time you call a method within the same class you violate the principle of isolation, which is key to unit testing. Why does calling a method from within the same class violate the principle of isolation? Because the methods are tightly coupled and it is no longer possible to test the calling method without also testing the called method. So what is the answer? Well, one way is to use collaborators. The objects can be used, stubbed or mocked for unit tests and the calling and called objects can be tested separately.

So what are some arguments against this type of pattern? Well, many people complain about the following points: (1) the code is no longer as readable, (2) the visibility of the code is changed, (3) the potential explosion of classes, and (4) the logic of an "Object" is no longer contained within the class. Let's discuss these points one at a time. Code samples are included below for a side-by-side comparison so read the code and think about it as you go through the four points.

1) The code is no longer as readable. This may be the point with the most merit. Instead of reading the code and simple scrolling up or down to continue reading the reader must now find another class. Having a method name on the called class that is descriptive often makes the code just as readable, it simply requires the reader to go to another place to read the details of the implementation. IDE's alleviate this by allowing users to jump to other classes/methods.

2) The visibility of the code is changed. Instead of having a private or protected method inside of the class there is now an often times public method on another interface/class. However, the scope of the collaborator can be controlled inside the class so in my opinion the benefit of testability outweighs the changing of scope from method to field.

3) The potential explosion of classes. Methods can still be grouped together on collaborators by related functionality, but having a few extra classes is an acceptable trade-off for more testable code. Classes often tend to be simpler with this methodology. This can become an argument of preference between fewer, more complex classes or more classes that are simpler.

4) The logic of an object is no longer contained with the class. But it can be contained within a small number of classes in the same package and the classes tend to be simpler and classes tend to be even more well defined in terms of what they do.

There probably is no right or wrong answer here, to a degree it is a matter of preference, however, I feel pretty strongly that having more testable code without any major drawbacks is worth adopting this pattern. This pattern works particularly well when the called code is a stateless service that can be injected by an IOC container, such as Spring.

Let's look at samples side by side.

# All the logic in one class (NOT easily testable because bar must be tested with foo)

public class Foobar {
  public void foo() {
    for ( int i = 0; i < 10; i++ ) {
      bar();
    }
  }

  public void bar() {
    // do bar
  }
}
# Using collaborator (foo and bar can be tested completely independent of each other)

public class Foo {
  private Bar bar;

  public void setBar(Bar bar) {
    this.bar = bar;
  }

  public void foo() {
    for ( int i = 0; i < 10; i++ ) {
      bar.bar();
    }
  }
}

public class Bar {
  public void bar() {
    // do bar
  }
}
Posted by bweber Oct 23 2007, 12:03:38 AM EDT
20070730 Monday July 30, 2007
JRuby script in a signed jar OK, let's dive into the world of JRuby a little further, specifically let's touch on the boundary between Java and JRuby again. One excellent way to run JRuby for certain situations is to put the JRuby code (along with some Java code) in a signed, executable jar. A fairly common reason to do this would be the following: you want to run some ruby code (in the JVM) and you want to make sure that no one modifies the contents of the JRuby file (thus you sign the jar). Of course this does not offer you perfect protection, but it adds another layer making it more difficult to subvert your efforts. For the time being, I will assume that you have JDK 1.5 and not JDK 1.6... which means that the scripting framework is not available to you. So, simply include the JRuby jar file in your classpath and jar up the following class along with your ruby files. You should be sure to sign the jar when you create it and you should add pkg.JRubyRunner as your main class so the jar file is executable. Then executing "java -cp jruby.jar -jar MyJar.jar" will run your jruby code AND since the jar file is signed no one will be able to modify your ruby files! (Again, with some effort of course a hacker could modify the ruby file if they had access to the jar.)
package pkg;

import org.jruby.Main;

public class JRubyRunner {
  public static void main(String[] args) throws Exception {
    runJRubyScript("ipc.rb", args);
  }

  public static void runJRubyScript(String name, String... args) {
    // modify the args for jruby
    String[] args2 = new String[2 + args.length];
    if (args.length > 0) {
      System.arraycopy(args, 0, args2, 2, args.length);
    }
    args2[0] = "-e";
    args2[1] = "require '" + name + "'";
    // execute the ruby script
    Main.main(args2);
  }
}

Now, for a few subtle points that you may have missed, especially considering the simplicity of the code. For starters, why you may ask, not just pass in the name of the ruby file? Why use the -e option at all? Well, the reason is because the ruby file is located in the jar file so it is not accessible via java.io.File which JRuby uses to load the file. This makes perfect sense. And since it defeats the purpose to move the ruby file outside of the signed jar, we must find another way to get this to work. You could read in the entire contents of the file from the classpath and pass it into the -e option, but this is ugly and extremely prone to error, so we take advantage of an excellent feature of 'require' in JRuby. Require loads its files from the classpath. This is excellent, because it means that if we require just the file we want to run, it will be loaded from the classpath and and subsequent requires will be loaded from the classpath as well.
Posted by bweber Jul 30 2007, 09:28:15 PM EDT
20070704 Wednesday July 04, 2007
Configuring JRuby in IntelliJ IDEA 6.0.5 So you know Java, you've played around with Ruby and now you are interested in trying out JRuby in your favorite IDE (which naturally is IntelliJ IDEA) or maybe you just want to try out Ruby/JRuby... Unfortunately, JetBrains is still a little behind with their Ruby, and especially JRuby, support for IntelliJ. But have no fear, just follow the steps below and you'll be up and running without too much trouble.

[Legal disclaimer: This was tested on Mac OS X with Java 1.5, JRuby 1.0 and IntelliJ 6.0.5, but should work on any Windows or *nix based system with IntelliJ 6.0.x and the JRuby 0.1 plugin.]

[Legal disclaimer: The screen shots in these instructions are not actually perfect or exactly what you will see at all stages of the process, however they should contain all the information required.]

  1. Install Ruby Plugin for IntelliJ Instructions (Leaves this page) [Don't look for a JRuby plugin, install the Ruby plugin.]
  2. Download and Install JRuby (unzip to the desired installation directory) Instructions (Leaves this page)
  3. [UPDATE: I PUT IN A FEATURE REQUEST AND JETBRAINS INCLUDED IT SO NOW THERE IS SUCH A THING AS A JRUBY SDK SO THIS STEP IS NO LONGER REQUIRED! YEAH JETBRAINS!!!!] Create a Ruby link (*nix) or bat file (Windows) [UPDATE: Creating a bat file named ruby.bat does NOT work. IntelliJ looks for ruby.exe which makes this trick more of a pain... On Windows it is probably simpler to create an External Tool for JRuby right now. That way you can right click on a file and execute it and it doesn't require any fancy hacks. Instructions for creating/configuring the "external tool" are below.] that points to the JRuby executable [The IntelliJ plugin requires the executable file be called "ruby" and not "jruby" so we simply trick it by creating a file that points to the real JRuby executable. Hopefully JetBrains will change this for future releases.]
    • *nix soft link: ln -s jruby ruby
  4. Create a project with a Ruby module (note: create a Ruby module NOT a JRuby module as you won't find any such thing as a JRuby module. Nor do you need one for that matter, as the Ruby module will do just fine thank you very much. I suppose that JRuby wouldn't be very good if it couldn't just replace Ruby as that is what it is designed to do after all! Well, sort of anyway.)


  5. Point IntelliJ to your JRuby SDK



So now you can execute Ruby files using JRuby as your runtime in IntelliJ. But what if you want to call out to some Java code? In JRuby you have to manage the classpath if you want to call out to java classes. You can do this by setting the $CLASSPATH environment variable or by using the $CLASSPATH global variable. (which is only accessible after you have executed the " require 'java' " statement) Unfortunately, IntelliJ does not set either value when including a Java module. To be fair, the latter case wouldn't really be possible because of the sequencing that is required, but hopefully they do add support so that in the future the $CLASSPATH environment variable is set automatically for you so classpath dependencies can be managed by the IDE just like for other projects/modules.

The EASY CASE (Ruby modules only)

  1. Create java_cp file and enter classpath values [NOTE: Classpath values must end with a trailing slash due to the implementation of the java module in JRuby.]

  2. Include java_cp after java and before including any classes

  3. Run files by right clicking on the file and choosing Run or by selecting the file and hitting the Run shortcut key sequence.

The HARDER CASE (Ruby modules and Java modules in the same project)

  1. Change the ruby project SDK to Java (Otherwise your Ruby module will be fine but your Java modules will not work due to a bug in the Plugin.)

    See, I told you, you get an irrelevant, nasty error message!

  2. Create a JRuby External Tool (Carefully note the parameters and working directory used. Notice that I made the working directory the lib directory where I put my source file(s). This screen shot is inconsistent with the other screen shots taken because it came from another project, so just take my word for it. :))

  3. Run your Ruby files by selecting the file and choosing Tools -> JRuby.

So, there currently is not a perfect solution for running JRuby in IntelliJ IDEA, however these few steps should get you up and running in a minimal amount of time. In the simple case there are only really two steps that are required that wouldn't be present if you were just using the Ruby plugin itself: creating the link to the executable file and managing the classpath manually (in this case via an included file jruby_cp).

Posted by bweber Jul 04 2007, 10:20:46 PM EDT