by Teera Kanokkanjanarat
Before you proceed, make sure you review the requirements in this section.
This tutorial assumes that you have some basic knowledge of, or programming experience with, the following technologies.
Before you begin, install the following software on your computer:
The first step is to make sure that you have JRuby installed correctly on your machine.
1. By default, Netbeans 6.0 beta 1 ships with JRuby interpreter version 1.0.1. If you want to use another version of JRuby, you will have to point the IDE to the downloaded JRuby binary location.
2. Start the Netbeans IDE.
3. Go to the Ruby configuration setup panel.
* On Windows, go to the main menu and choose Window > Options. This will open the Options dialog box. Select Ruby. * On Mac OS X, go to the main menu and choose Netbeans > Preferences. This will open the Options dialog box. Select Ruby.
Figure 1: Pointing Netbeans to an installed JRuby interpreter
4. On the Ruby Options panel, make sure that Ruby interpreter points to the correct location of the installed JRuby binary executable.
5. For more detailed information on how to setup the JRuby and Ruby plugins on Netbeans, click here .
1. On your favorite web browser, navigate to the url http://www.webservicex.com/CurrencyConvertor.asmx.
2. You will see that this service offera one operation which is ConversionRate and also a list of valid currency codes.
3. Next, you can navigate to http://www.webservicex.com/CurrencyConvertor.asmx?WSDL to inspect the WSDL description of this web service. We will later create a Ruby web service client based on this WSDL file.
1. In the main menu, choose File > New Project> Ruby > Ruby Application.
Figure 2: Creating Netbeans Ruby project 'JRubyCurrencyConverter'

2. Explore the project structure. In the project panel, create the following folders under 'Source Files' folder: service, view, module, model, java, action, log.
3. Under the 'service' folder, create new ruby class. Name the class 'CurrencyConverterService' and name the file 'currency_conversion_service.rb'. This class will be used as client component consuming the web service.
Figure 3: Setting up the source folder structure and creating the CurrencyConverterService Ruby class
4. Open the currency_conversion_service.rb file, add the code "require 'soap/wsdlDriver'" at the top. We need SOAP WSDL module from Ruby standard library to make SOAP web service call.
5. Optional: add the code "attr_accessor :wsdl, :from_currency, :to_currency" to this service class to provide access to service's attributes.
6. In the constructor of CurrencyConverterService class, add two parameters that take in the converting currency code and desired currency code. We will also initialize the web service proxy and SOAP message log file location .
Code Example 1: CurrencyConverterService class constructor
require 'soap/wsdlDriver' #loading SOAP/WSDL Ruby standard library module
class CurrencyConversionService
attr_accessor :wsdl, :from_currency, :to_currency #optional variable accessors
#constructor
def initialize(from_currency, to_currency)
@wsdl = 'http://www.webservicex.com/CurrencyConvertor.asmx?WSDL'
@from_currency = from_currency
@to_currency = to_currency
@driver = SOAP::WSDLDriverFactory.new(@wsdl).create_rpc_driver #initialize the call
@driver.wiredump_file_base = './log/currency_conversion_service_log' #set the log file location
end
...
end
7. Next, create another method that makes a call to the web service operation via the proxy we have created in the constructor.
Code Example 2: Making the SOAP web service call
require 'soap/wsdlDriver' #loading SOAP/WSDL Ruby standard library module
class CurrencyConversionService
...
#calling 'ConversionRate' web service operation
def call
parameters = {:FromCurrency => @from_currency, :ToCurrency => @to_currency}
result = @driver.ConversionRate(parameters) #make the call
puts 'result = ' + result['ConversionRateResult'].to_s
return Float(result['ConversionRateResult'].to_s)
end
end
Note: 'ConversionRate' operation takes two parameters and returns the value of type double
1. There are two ways to include Java libraries in a Netbeans Ruby project.
* Under the project properties panel > Java, you can specify which Java libraries are to be included in the project during compile time. Once you specify the library here, it will be accessible from anywhere in the project
Figure 4: Including Java libraries in Netbeans Ruby project
* Another option is to include the jar files in the project source folder. Simply copy swing-layout-<version-number>.jar and paste it somewhere in your project source code. If you choose this option, you will have to include the file directory when you want to use it. In this tutorial I use swing-layout-1.0.2.jar and I put it under 'Java' folder created earlier.
Note #1: Where should I put jar files in my Ruby project ?
You can actually put the .jar files anywhere in the project. When you want to access it, you just have to the relative path from
the root directory to that jar file. For example, if you put Foo.jar under "<NETBEANS_PROJECT>/lib/folder1/", when you want to
refer to this class libraries in ruby code, you'll have to add
require 'java'
require 'folder1/Foo.jar'
I usually put all class libraries and everything related to java in one place ('java' folder) for easy access
1. Under the 'module' folder, create a new Ruby module called 'Swing' with file name 'swing.rb'.
2. Including Java packages and classes for Java Swing API that we will use.
Code Example 3: Swing Module
require 'java'
require 'java/swing-layout-1.0.2.jar'
module Swing
include_package 'javax.swing'
include_package 'javax.swing.event'
include_class 'org.jdesktop.layout.GroupLayout'
include_class 'org.jdesktop.layout.LayoutStyle'
JOptionPane = javax.swing.JOptionPane
end
3. Under the'module' folder, create a new Ruby module called 'Awt' with file name 'awt.rb'. Include java.awt and java.awt.event packages in this module.
Code Example 4: AWT Module
require 'java'
module Awt
include_package 'java.awt'
include_package 'java.awt.event'
end
4. Under 'module' folder, create a new Ruby module called 'Lang' with file name 'lang.rb'. Include java.lang package in this module.
Code Example 5: Lang Module
require 'java'
module Lang
include_package 'java.lang'
end
Note #2: Do I need to create module for all Java APIs ?
You don't have to create Ruby module to wrap around a Java API. With JRuby, you can access Ja ava class directly from the Ruby code. For example, you can do frame = javax.swing.JFrame.new directly. I found that Java package names are often very long! Creating a wrap around module can help you make the call easier. As you will see in the next section, wrapping javax.swing in Swing module allows me to create a JFrame object with shorter and cleaner code, frame = Swing::JFrame.new.
Since we will be displaying a list of currencies with names of countries, it would be convenient to have a Currency object to encapsulate that information.
1. In the 'model' folder we created earlier, create a new Ruby class called 'Currency', file name 'currency.rb'.
Figure 5: Creating Currency object

2. This Currency class will hold the currency code and country name.
Code Example 6: Ruby Currency object class
class Currency
attr_accessor :code, :name
#constructor
def initialize(code, name)
@code = code
@name = name
end
#called by combobox model to display country name to user
def to_s
return @name.to_s
end
end
We will go ahead and implement the user interface in Ruby with Swing API.
1. In the 'view' folder we created, create a new Ruby class called ConverterView, file name 'converter_view.rb'.
2. At the top of the class file, we need to explicitly specify the required module for swing. We also would like our ConverterView class to subclass Swing's JFrame.
Code Example 7: Including Swing module in the view and subclassing JFrame
require 'java' require 'module/swing' require 'module/awt' require 'module/lang' require 'model/currency' class ConverterView < Swing::JFrame
3. Next we will add the implementation detail of the view class. Some details are omitted here for brevity. For the full code listing please refer to the source file.
Code Example 8: View implementation
#constructor
def initialize(title)
super(title)
initComponents
end
#control the display of this UI
def display(is_visible)
self.setVisible(is_visible)
end
def get_user_input
return {'value' => @txtConvertingValue.getText,
'from' => @ddlFromCurrency.getSelectedItem().code,
'to' => @ddlToCurrency.getSelectedItem().code}
end
#display conversion result
def show_converting_result result
@lblResult.setText(result.to_s << ' ' << @ddlToCurrency.getSelectedItem().to_s)
end
private
def initComponents
...... # detail omitted here for brevity
end
#Adding currency we would like to convert
def create_currency_code_model
model = Swing::DefaultComboBoxModel.new
model.addElement Currency.new('USD', 'US $')
model.addElement Currency.new('CAD', 'Canadian $')
model.addElement Currency.new('CNY', 'Chinese Yuan')
model.addElement Currency.new('EUR', 'Euro')
model.addElement Currency.new('JYP', 'Japanese Yen')
model.addElement Currency.new('KRW', 'Korean Won')
model.addElement Currency.new('THB', 'Thai Baht')
model.addElement Currency.new('AUD', 'Australian $')
return model
end
4. And that's it! Now we would like to test the UI. We can do this by modifying main.rb to construct the ConverterView object and pop it up.
Code Example 9: Modify main.rb to test our UI
require 'view/converter_view'
puts "Swing with JRuby!"
view = ConverterView.new 'JRuby Currency Converter'
view.display(true)
5. If you run the main.rb source file attached with this tutorial, this will show up.
Figure 6: Running the JFrame UI
Note #3: Creating a great looking GUI without having a headache
Developers who are not familiar with Swing may find it quite a challenge taking on Swing (especilly from Ruby!). I myself am not Swing expert by any measures. Fortunately, JRuby allows developers to port much of Java code to the Ruby side by simply changing the syntax and style. The APIs most often remain the same. Netbeans IDE ships with Matisse GUI Builder. So, why not leverage the tool we have? In this example, I create a simple Java GUI project, create the converter UI using Matisse, and simply port the code directly to JRuby!
So, now we have our logic (web service call), model (Currency), and view (ConverterView). It's time to add the last piece of the puzzle, the button action!
1. Under the folder 'action' we created earlier, create a new class call "CurrencyConverterAction_ConvertButton_Clicked", file name "currency_converter_action.rb".
2. This action class will be fired when the user clicks the 'Convert' button.
3. This action class will subclass ActionListener and override its actionPerformed method.
Code Example 10: CurrencyConverterAction_ConvertButton_Clicked
class CurrencyConverterAction_ConvertButton_Clicked
include Awt::ActionListener
#constructor
def initialize(view)
@view = view
end
#Overriding this class
def actionPerformed(event)
user_input = @view.get_user_input
converting_value = user_input['value']
#assigning empty value to zero
if converting_value.to_s.strip == ''
converting_value = 0
end
#validate
begin
converting_value = Float(converting_value)
rescue ArgumentError
Swing::JOptionPane.showMessageDialog(@view, 'Error: ' + converting_value.to_s+ ' is not a valid numerical value.', 'Error: Invalid input', Swing::JOptionPane::ERROR_MESSAGE)
return
end
converting_from = user_input['from']
converting_to = user_input['to']
puts 'value = ' << converting_value.to_s << ', currency = ' << converting_from.to_s << ', to = ' << converting_to.to_s
#same currency, don't even bother making web service call!
if(converting_from == converting_to)
@view.show_converting_result converting_value.to_s
return
end
#Calling the service and send result back to the view
@view.show_converting_result round(CurrencyConversionService.new(converting_from, converting_to).call.to_f * converting_value, 3)
end
private
#Rounding float value to specific decimal digit
def round(float, num_of_decimal_places)
exponent = num_of_decimal_places + 2
float = float*(10**exponent)
float = float.round
float = float / (10.0**exponent)
end
end
4. As you can see, when a user clicks the 'Convert' button, the actionPerformed method is fired. The code will proceed to validate user input, call a web service for conversion, and send the result back to the view for display.
5. In this last step, we hook up this event to the button in the view.
Code Example 11: Wiring action event to the view's initComponents method
def initComponents
.....
@btnConvert.setText 'Convert'
@btnConvert.addActionListener CurrencyConverterAction_ConvertButton_Clicked.new(self)
....
end
6. And that's it!
Figure 7: JRuby Currency Converter in action

This tutorial walks you though how you can leverage JRuby, Swing API, and Netbeans IDE to create a desktop application with the Ruby programming language. Developing desktop applications with JRuby run on the Java Virtual Machine. So I strongly believe that JRuby will help Ruby make the transition from web (on Rails framework) to take advantage of the desktop platform.
| JRubyCurrencyConverter.zip | ![]() |
75017 bytes |
| apserverstartupscaled.png | ![]() |
54316 bytes |
| flash_demo_button_med.gif | ![]() |
1372 bytes |
| jrubyswing1.png | ![]() |
124198 bytes |
| jrubyswing2.png | ![]() |
51368 bytes |
| jrubyswing3.png | ![]() |
21468 bytes |
| jrubyswing4.png | ![]() |
46747 bytes |
| jrubyswing5.png | ![]() |
14755 bytes |
| jrubyswing6.png | ![]() |
20483 bytes |
| jrubyswing7.png | ![]() |
21666 bytes |