October 9th, 2006
JRuby presentation in Malmö
It is now final that I will be presenting JRuby at JavaForum in Malmö, the 30:th October. There is more information available at www.javaforum.se.
It is now final that I will be presenting JRuby at JavaForum in Malmö, the 30:th October. There is more information available at www.javaforum.se.
OK, for those of you who thought that importing a class into the current namespace by assigning a constant, here is a small implementation (based on include_class), that lets you use import like you do it in Java:
require 'java'
class Object
def import(name)
unless String === name
name = name.java_class.inspect
end
class_name = name.match(/((.*)\.)?([^\.]*)/)[3]
clazz = self.kind_of?(Module) ? self : self.class
unless clazz.const_defined?(class_name)
if (respond_to?(:class_eval, true))
class_eval("#{class_name} = #{name}")
else
eval("#{class_name} = #{name}")
end
end
end
end
import java.util.TreeMap
x = TreeMap.new
x['foo'] = 'bar'
puts x
I thought that I should post a little notice about what’s happening with JRuby right now. Most of this is available for you if you subscribe to FishEye for JRuby (http://fisheye.codehaus.org/changelog/~rss/jruby/rss.xml).
There are a few very nice innovations going on. The most important is probably that Java-integration has been improved quite substantially. Basically, if the package you need are in the java, javax, org or com packages, you can just refer to classes the same way you refer to them in Java (except for classes that doesn’t have a capital initial letter, but you don’t do that, do you?). Typical JRuby code could look like this:
require 'java'
TreeMap = java.util.TreeMap
x = TreeMap.new(java.util.Comparator.impl { |m,o1,o2|
o1 <=> o2
})
Now, there are two new features in here, and one JRuby idiom that should be used in JRuby code. The first feature is to refer to classes by name, simply. The idiom is to import classes into the current namespace by assigning them to constants. The second interesting feature is the ‘impl’ method, that is available on all interfaces. This method will create an anonymous implementation of the interface, which will call the block when any of the methods in the interface is called. The method name goes in the parameter ‘m’ in the example. This allows a very clean syntax for implementing one-method-interfaces, like in the example above. Before these we’re added, you had to use import_class for each class, then create a class for the interface, and then use this class. The code would easily have doubled for this example.
A few days ago Charles and Tom made me committer in the JRuby project, which obviously feels very good, though slightly nervous. But I’ve been able to fix a number of very small bugs since then. The more interesting of these, in no order:
There are a few things being discussed on the list right now. We will soon commit a readline.rb that checks if the JNI-based GNU readline-bridge is present, and if so uses it. This means that if you want, you can have basic readline in JIRB.
We are talking about the best way to implement OpenSSL support too. This is quite a big thing, though, and as Tom put it “It will be pretty difficult but the person who does it will be worshipped”. I’m not sure about the right way to go with implementation either. It seems the available OpenSSL JNI-implementations aren’t good enough, so the best route seems to be JSSE. If you have any opinions or suggestions, please get in touch.
In other news, it seems I’m going to be talking about JRuby at JavaForum in Malmö. The date is not final but it seems likely to be the 23 October. If you’re in Malmö, please stop by. I’ll post more information as soon as everything is clear.
Version 0.2.2 of ActiveRecord–JDBC have now been released. It contains numerous smaller bug fixes, but more importantly the support for MimerSQL. The internals have been slightly refactored to allow easier change of database specific instructions further down the road.
The release can be found at http://rubyforge.org/frs/?group_id=2014 or installed through RubyGems.
This part of the tutorial will be based on some slightly not-released software, but since it is so cool, I bet you will try it anyway. Basically, what I’m going to show you is how to get Mongrel 0.4 working with JRuby, and then how you can serve your JRuby on Rails-application with said version of Mongrel.
What you’ll need
First of all, check out the latest trunk version of JRuby. There are some smoking new fixes in there that is needed for this hack. Next, you will also need to check out the 0.4-branch of Mongrel. This can be done with the following command:
svn co svn://rubyforge.org/var/svn/mongrel/branches/mongrel-0.4
You need to manually copy two parts of mongrel into your JRuby home. If $MONGREL_SRC is the name of the directory where you checked out mongrel, these commands will suffice:
cp -r $MONGREL_SRC/lib/mongrel* $JRUBY_HOME/lib/ruby/site_ruby/1.8
cp $MONGREL_SRC/projects/gem_plugin/lib/gem_plugin.rb $JRUBY_HOME/lib/ruby/site_ruby/1.8
echo '#\!/usr/bin/env jruby' > $JRUBY_HOME/bin/mongrel_rails
cat $MONGREL_SRC/bin/mongrel_rails >> $JRUBY_HOME/bin/mongrel_rails
chmod +x $JRUBY_HOME/bin/mongrel_rails
You will need to download the JRuby-specific http11-extension library. This can be downloaded here, and should also be put in the $JRUBY_HOME/lib/ruby/site_ruby/1.8-directory.
You’re now set to go.
Simple web hosting
I will now show how to set up at small web server, that can serve both files and servlets. There really isn’t much to it. First of all, we need to include some libraries:
require 'mongrel'
require 'zlib'
require 'java'
include_class 'java.lang.System'
Next step is to create a simple HttpHandler (which is like a Servlet, for you Java-buffs):
class SimpleHandler < Mongrel::HttpHandler
def process(request, response)
response.start do |head,out|
head["Content-Type"] = "text/html"
results = <<-"EDN";
<html>
<body>
Your request:<br/>
<pre>#{request.params.inspect}</pre>
<a href=\"/files\">View the files.</a><br/>
At: #{System.currentTimeMillis}
</body>
</html>
EDN
if request.params["HTTP_ACCEPT_ENCODING"] == "gzip,deflate"
head["Content-Encoding"] = "deflate"
# send it back deflated
out << Zlib::Deflate.deflate(results)
else
# no gzip supported, send it back normal
out << results
end
end
end
end
Now, this handler basically just generates a bunch of HTML and sends it back. The HTML contains the request parameters. Just to show how easy it is to combine Java-output with Ruby-output, I have added a call to System.currentTimeMillis. This could of course by anything. The last part is to actually make this handler active also. To finalize, we also start the server:
@simple = SimpleHandler.new
@http_server = Mongrel::HttpServer.new('0.0.0.0',3333)
@http_server.register("/", @simple)
if ARGV[0]
@files = Mongrel::DirHandler.new(ARGV[0])
@http_server.register("/files", @files)
end
puts "running at 0.0.0.0:3333"
@http_server.run
If you start this script with:
jruby testMongrel.rb htdocs
you can visit localhost:3333 and expect to see some nice output.
Making it work with Rails
A prerequisite for this part is that you have a functional JRuby on Rails-application using ActiveRecord-JDBC. If that is the case, you just need to go your application directory and execute this command:
$JRUBY_HOME/bin/mongrel_rails --prefix "" start
and everything should just work.
So, that’s it. JRuby on Rails, with Mongrel. Enjoy.
An hour ago I sent the patches to make JRuby’s YAML support completely Java-based. What I have done more specifically, is to remove RbYAML completely, and instead used the newly developed 0.2-support of JvYAML. There were a few different parts that had to be done to make this possible, especially since most of the interface to YAML was Ruby-based, and used the slow Java proxy-support to interact with JvYAML.
So, what’s involved in an operation like this? Well, first I created custom versions of the Representer and the Serializer. (I had a custom JRubyConstructor since May). These weren’t that big, mostly just delegating to the objects themselves to decide how they wanted to be serialized. And that leads me to the RubyYAML-class, which is what will get loaded when you write “require ‘yaml'” in JRuby from now on. It contains two important parts. First, the module YAML, and the singleton methods on this module, that is the main interface to YAML functionality in Ruby. This was implemented in RbYAML until now.
The next part is several implementations of the methods “taguri” and “to_yaml_node” on various classes. These methods are used to handle the dumping, and it’s really there that most of the dumping action happens. For example, the taguri method for Object says that the tag for a typical Ruby object should be “!ruby/object:#{self.class.name}”. The “to_yaml_node” for a Set says that it should be represented as a map where the values of the set are keys, and the values for these keys are null.
So, when this support gets into JRuby trunk it will mean a few things, but nothing that is really apparent for the regular JRuby user. The most important benefits of this is part performance, and part correctness. Performance will be increased since we now have Java all the way, and correctness since I have had the chance to add lots of unit tests and also to fix many bugs in the process. Also, this release makes YAML 1.0-support a reality, which means that communication with MRI will work much better from now on.
So, enjoy. If we’re lucky, it will get into the next minor release of JRuby, which probably will be here quite soon.
The last few days have been spent integrating the JvYAML dumper with JRuby, and also to make YAML support in JRuby totally implemented in Java. As a side effect I have been able to root out a few bugs in JvYAML. Enough of them to warrant a minor release, actually. So, what’s new? Working binary support, support for better handling of null types, better 1.o-support and a few hooks to make it possible to remove anchors in places where it doesn’t make sense. (Like empty sequences.)
The url is http://jvyaml.dev.java.net and I recommend everyone to upgrade.