Saturday, December 15, 2007

NetBeans 6.0 and Rails

I have been looking for a good Rails IDE and think I have found one. I was using TextMate which has lots of great quick templating commands for Rails concepts for migrations, rhtml, and navigating between files and methods. However, I enjoy working with IDEs and tried some Eclipse based versions but felt that they were inadequate. My paying job at the time is mostly Java based and I use IntelliJ which makes my development more productive for that type of development.

I had not looked at NetBeans in some time because most Java developers were using Eclipse and that was fine for me at the time. So when I saw that NetBeans had a Rails related version of their IDE I was willing to give it another look. I can only say that for me this is a very nice IDE that has full functionality around the way I develop with Rails. Here are some of the features I find handy:

  • A simple IDE layout for components that is similar to IntelliJ. There are no unnecessary perspectives that Eclipse users have.
  • Support for auto-completion of methods with rdoc helpers.
  • Debugging capabilites that are simple to use.
  • Integration with version control repositories like Subversion.
  • Tools to manage your Gems and Plugins from the Tools menu
  • Easy navigation between Rails controllers and views as well as opening files via keystrokes.
  • Decent refactoring built in
  • Generators for creating Rails components.
  • Menus to run Rake and Migration scripts
  • Built in functionality to start a Rails console from your project
  • It works great on my Mac and much more than I expected...


  • Just to whet your appetite to get you more excited about this IDE here are a couple of screenshots from how I use this IDE:
    Here is what it looks like when editing files with code completion and quick docs:



    And here is a shot of what debugging looks like in NetBeans:



    If you are working on a Mac make sure you look at this link for setting up the fast debugger gem. You will also need to have XCode installed for compilation.
    I think you will agree that this is the best IDE for Rails at this time.

    Monday, March 5, 2007

    Java Through Ruby Through Java

    Java => Ruby

    Now that JRuby has matured I thought I would see what it would take to inject Java objects into Ruby objects via a Spring context. Here is how this works:

    First, create a Ruby class that will receive your Java objects:

    ruby_messenger.rb:

    require 'java'

    include_class 'com.meagle.common.spring.jruby.JRubySpring'
    include_class 'com.meagle.common.service.UserService'
    include_class 'com.meagle.common.service.impl.BaseUserServiceImpl'

    class RubyMessenger < JRubySpring

    def printMe
    p @@message
    p @@userService.to_s
    user = @@userService.findUser('admin')
    p "User first name: #{user.firstName}"
    #p user.to_xml
    end

    def setMessage(message)
    @@message = message
    end

    def getMessage
    @@message
    end

    def setUserService(userService)
    @@userService = userService
    end

    end

    RubyMessenger.new # this last line is not essential (but see below)
    This class will receive a user service object that allows us to make calls to a transactional Spring bean to a DAO defined in the main Spring configuration.

    Furthermore, I am injecting a simple String into the Ruby class from the Spring context called 'message'. Notice that the class extends an interface in Java called JRubySpring. This interface is used to expose methods on the Ruby object to our Java application. Here is what this Java interface looks like:

    JRubySpring.java:

    public interface JRubySpring {
    void printMe();

    void setUserService(UserService service);

    String getMessage();

    void setMessage(String message);
    }
    Now we have to tell Spring about our Ruby class and the properties to inject into the class. This can be wired up in a Spring 2.0 context configuration file like this:

    applicationContext-jruby.xml

    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:lang="http://www.springframework.org/schema/lang"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://www.springframework.org/schema/lang
    http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">

    <?xml version="1.0" encoding="UTF-8"?>

    <lang:jruby id="jrubyService"
    script-interfaces="com.meagle.common.spring.jruby.JRubySpring"
    script-source="classpath:ruby_messenger.rb">

    <lang:property name="message" value="Hello from Ruby!"/>

    <lang:property name="userService">
    <ref bean="userService"/>
    </lang:property>

    </lang:jruby>

    </beans>

    This instructs Spring to use the ruby_messenger.rb class from the classpath and allow Java classes to use the JRubySpring interface to invoke methods on the Ruby class. Furthermore, you can see the properties that are being injected into the Ruby class here.

    Finally, we need a way to test this out. Again, Spring can help us test this using the AbstractSpringIntegrationTestBase class to help with initializing a Spring context and running test scenarios. Here is the test class:

    JRubySpringTest.java

    public class JRubySpringTest extends AbstractSpringIntegrationTestBase {
    private UserService userService;

    public JRubySpringTest() {
    setDefaultRollback(true);
    }

    protected String[] getConfigLocations() {
    return new String[]{
    "applicationContext-core.xml",
    "applicationContext-jruby.xml"
    };
    }

    JRubySpring jrubyService;

    public void testGetUser() {
    System.out.println("Printing messages from plain old Java Spring context...");
    System.out.println(jrubyService.getMessage());
    User user = userService.findUser("admin");
    System.out.println("user = " + user.getFirstName());
    System.out.println("Printing messages from a Spring context injected
    into a Ruby object...");
    jrubyService.printMe();
    }

    public JRubySpring getJrubyService() {
    return jrubyService;
    }

    public void setJrubyService(JRubySpring jrubyService) {
    this.jrubyService = jrubyService;
    }

    public void setUserService(UserService userService) {
    this.userService = userService;
    }
    }
    This test class will initialize Spring and autowire the Ruby class into the test class with the Java/JRuby properties injected into the Ruby class as singletons.




    Here is some sample output when running this test class:

    03.05.2007 13:30:40,062 INFO dao.hibernate.JRubySpringTest.startNewTransaction:318 ->
    Began transaction (1): transaction manager [org.springframework.orm.hibernate3.HibernateTransactionManager@1284f8e]; default rollback = true

    Printing messages from plain old Java Spring context...

    Hello from Ruby!

    user = System

    Printing messages from a Spring context injected into a Ruby object...

    "Hello from Ruby!"


    "com.meagle.common.service.impl.BaseUserServiceImpl@595bcd"

    "User first name: System"

    03.05.2007 13:30:40,312 INFO dao.hibernate.JRubySpringTest.endTransaction:284 ->
    Rolled back transaction after test execution
    03.05.2007 13:30:40,328 INFO context.support.ClassPathXmlApplicationContext.doClose:599 ->
    Closing application context [org.springframework.context.support.ClassPathXmlApplicationContext;hashCode=6504030]

    Ruby => Java

    So what if you want to have an irb session and communicate with your Java objects. For this you just need your existing Spring context and a bootstrapping file for Ruby to initialize a JRuby console. It goes like this:

    jruby_console.rb

    # To use JRuby and Java Spring contexts together do the following:
    #
    # 1. Download the JRuby irb jar file from:
    # http://jruby.codehaus.org/Running+the+JRuby+Console+(graphical+IRB)
    #
    # 2. Add the jruby-console-0.9.2.jar file to your Java project classpath
    #
    # 3. Create a new configuration to run a Java application and set the main class to
    # org.jruby.demo.IRBConsole
    #
    # 4. Of course make sure your classpath is set correctly for your Spring config and
    # other classes/jars you need to test.
    #
    # 5. Run the application which will load the JRuby irb console
    #
    # 6. In the irb window type > load 'jruby_console.rb' to initialize this script.
    #
    # 7. This will load your Spring configuration. Access your Spring beans as
    # instance variables like this @beanName.
    #
    # 8. That was easy

    require 'java'

    # require this file if you want to include your domain objects instead of
    # including them one at a time.
    require 'domain_core.rb'

    # include this line to include all of your specific Java domain objects
    include Domain::Core

    include_class('org.springframework.context.support.ClassPathXmlApplicationContext')

    springConfigs = ["applicationContext-core.xml"]
    @context = ClassPathXmlApplicationContext.new(springConfigs.join(","))

    if @context.nil?
    p "*********Could Not initialize Spring context*********"

    return
    else
    p "*********Spring context initialized as @context*********"
    end

    p "(#{@context.beanDefinitionNames.length}) beans initialized in this context:"
    beans = ""

    # Assign non-abstract beans are initialized to instance variables.
    # Example: The 'userService' bean name will be accessible via the
    # instance variable '@userService'
    @context.beanDefinitionNames.sort.each do |bean|
    unless bean =~ /^abstract/
    instance_variable_set("@#{bean}", @context.getBean("#{bean}"))
    beans << bean + ", "
    end
    end

    p beans
    p "=========================================================================="
    p "Hey you - access your beans as instance variable like this @springBeanName"
    p "=========================================================================="

    Now you can do sadistic stuff like this:

     Welcome to the JRuby IRB Console

    irb(main):001:0> load 'jruby_console.rb'
    "*********Spring context initialized as @context*********"
    "(4) beans initialized in this context:"
    dataSource, sessionFactory, userDAO, userService"
    "=========================================================================="
    "Hey you - access your beans as instance variable like this @springBeanName"
    "=========================================================================="
    => true

    irb(main):002:0> user = @userService.find(33, User.new.class)
    => #

    irb(main):003:0> p user.firstName
    "Mark"
    => nil
    irb(main):004:0>