Pure Danger Tech


navigation
home

JRuby

07 Nov 2006

I had a good time tonight at the Gateway JUG attending a talk by Charles Nutter on JRuby, which is Ruby on the Java VM. Personally, I’m really excited to see Sun putting an investment in dynamic languages and considering changes to the JVM to better support them. Looking a few years down the line, Java (and the JVM) need to increase their support for dynamic and lighter weight languages to remain relevant.

I was particularly interested to hear that they are building support for scripting languages like JavaScript and Ruby into NetBeans and looking to bring the same level of refactoring support we see for Java into the IDE. This is a difficult thing to do but it’s a critical gap to close if dynamic languages are going to gain mainstream penetration.

Charles did a lot of interactive live examples with JRuby and I took a transcript of a lot of it, in case anyone from the meeting is interested. There were three code sessions focusing on Ruby, JRuby (Java integration), and Rails on JRuby. Here are transcripts from each.

Ruby:

x = ["foo", "bar", 1]      # literal syntax for arrays (heterogenous)
x = {:foo => "bar"}      # literal syntax for maps 
# :foo is a symbol (a string, with uniqueness and identity guarantees, like interned string)

# Define a method
def hello(name)
	puts "hello' + name
end

# Print out, using variable in string
puts "Hello #{name}"

# times operator on integer
10.times { puts "Hello" }

# block, for each x, print x over array
["foo", "bar"].each { |x| puts x }

# yield in a method
def greet
	yield "Greetings!" 		# yield to the block
end

# yield method with block
greet { |x| puts x }

# define class
class MyClass
        # constructor
	def initialize(name)
		@name = name
	end
	
        # method
	def display
		puts "My name is #{@name}"
	end
end

mc = MyClass.new("Joe")
mc.display

# reopen class and add to it
class MyClass			
	def display 
		puts "My name is REALLY #{@name}"
	end
end

# pre-existing instance has been changed as well
mc.display				

# to define a mixin, use a module
module Displayer		
	def display_times
                # method doesn't exist in module, but does when mixed in
		10.times { display }		
	end
end

# open the class again and include a mixin
class MyClass			
	include Displayer
end

# use the mixed in method
mc.display_times		

# metaprogramming - list methods on class and sort
mc.methods.sort	

# list all class methods minus all super class Object methods
mc.methods - Object.methods

# add command completion to irb
require 'irb/completion'	

# add a new method to the built-in Fixnum class
class Fixnum
	def prime?
		return true
	end
end

# Remove a method from a class		
class Fixnum
	undef prime?
end

# Alias methods to new names

# Inheritance
class MyClass < OtherClass

# exception handling in a method
begin
	raise "Hello"				# throw
	rescue Exception => e		# catch
	ensure puts "x"				# finally
	puts e.backtrace
end

# add method only to a particular instance (x in this case), not to a class
x = 5
class << x		
	def prime?		
		true
	end
end

x.prime?		# returns true
7.prime?		# fails

JRuby and Java:

require 'java'
java.lang.System.out.println("Hello")
System = java.lang.System
System.out.println("Yay!")

f = javax.swing.JFrame.new("My Frame")
f.set_size(200, 200)		# ruby casing converted to java casing
f.show		# frame shows up

f.set_size(300, 300)

b = javax.swing.JButton.new("Press me!")
f.content_pane.add(b)	# getters/setters JavaBean become like attributes
f.show

class MyListener < java.awt.event.ActionListener
	def actionPerformed(event)
		event.source.text = "Please don't press me again!"
	end
end

b.add_action_listener(MyListener.new)

include_class "java.util.ArrayList"	
# now available for use w/o namespace
# also way to pull in all classes in a package (but brute force search)

x = ArrayList.new		# treat ArrayList as Ruby array
x << "hello"
x.each { |y| puts y }

# also possible to add methods to ArrayList, but not available on Java side

# Ruby to Java -> 
#      bean scripting framework
#      implement interface
#      new Java scripting API

Rail on JRuby:

rails gateway_app
cd gateway_app/
jruby script/server

jruby script/generate controller Test hello			
# Test=controller, hello=action

(http://localhost:3000/test/hello)

test_controller.rb:
	class TestController < ApplicationController
		def hello
			@name = "Gateway"
		end
	end

hello.html:
	<h1>Test#hello</h1>
	<h2>Hello, <%=@name %></h2>

jruby script/generate migration create_person

vi db/migrate/001_create_person.rb	# 001 = version of the database
	class CreatePerson < ActiveRecord:Migration
		def self.up						
			create_table :people do |table|
				table.column :firstname, :string
				table.column :lastname, :string
				table.column :age, :integer
			end
		end
		
		def self.down
		end
	end

vi config/database.yml
	# edit the database config, whitespace is important
	adapter: jdbc
	url: jdbc:mysql://localhost/gateway_development
	username: gateway
	password: gateway
	driver: com.mysql.jdbc.Driver

vi config/environment.rb
	require 'active_record/connection_adapters/jdbc_adapter'
	
mysql
	create database gateway_development;
	grant all on gateway_development.* to 'gateway'@'localhost' identified by 'gateway';
	
rake db:migrate

jruby script/generate scaffold person

http://localhost:3000/people

vi app/models/person.rb
	
	class Person < ActiveRecord::Base
	end

Tags: , ,