Neurogami

The debut album
Maximum R&D
is out now!

Get it here ...

Monkeybars and Rawr updates

New-ish versions of Rawr , Monkeybars, and Swingset have been released.

There’s not anything really new. Code was checked to see that it was still playing nice with the latest JRuby (1.7.19, not the JRuby 900 pre-release). These gems have been updated because there have been assorted minor tweaks happening and it seems simpler to demarcate them before anything more changes.

Swingset was having issues loading the MiG layout jar depending on what starting directory you used to execute the jar created by Rawr, so a bit of code was added to help. Monkeybars now require that version of Swingset.

The Rawr README was updated to offer a bit of explanation on what Rawr does.

One of the tricky things with Rawr (and Monkeybars, by extension) is that a primary goal was to help build standalone redistributable programs. However, ever since Rubygems became a default feature of Ruby the use of gems may start to become invisible. That is, you forget you’re using libraries that are not part of standard Ruby.

Rawr works by generating a Main.java file that is part of an executable Java jar; this file in turn loads your program’s actual main file (typically main.rb, but that’s configurable). Rawr gathers up your project files and (typically) puts them all into this executable jar. There are options to have required files kept in other files, but the bottom line is that when Rawr is done you have a set of files containing all of the code your program needs. (These in turn can be packaged up into an .exe or .app file.)

Rawr and gems

If you want to use any gems you need to unpack them into your project and edit your Rawr configuration file to include them when your code gets bundled up. Your code will likely have to add some paths to $: so that things are found.

Rubygems used to be an add-on library, and to use a gem you needed to explicitly say that you wanted rubygems loaded and active. The Rubygems library works by altering the built-in Kernel.require method. So, used to be, if you forgot to be explicit about using rubygems and them tried to require a gem file you would get an error. You shouldn’t have been able to accidentally load a gem.

Now, as it happens, there were some devs who would litter their library code with calls to require 'rubygems'. Serious facepalming ensued the first time I saw this. I think it was in ActiveSupport. Of course, what that did was taint your entire project, because once that happened all subsequent calls to require would also include a search for gems. (A bit of history.)

For better or for worse this is now the default behavior of every Ruby program. Now you can just load gem files as you would any standard Ruby library.

The problem is that you can end up using gems in your code without quite realizing it. If you have become accustomed to using this or that gem library in your code it becomes very easy to forget it is not part of the standard distribution.

Rawr make no effort to warn you about this, and makes no effort to ensure that all the files referenced in your project are part of your project. And everything will work fine for you because you happen to have the needed files installed. However, when you ship the app to someone else things might be different.

Another problem with using gems in what should be a standalone program is that an end user may a needed gem, but a version different from what the code wants. (If your code is dependant on using a specific gem version you should be requiring it with the version indicated.)

Basically, you will most likely be better served by including all needed files in you project and not relying on gems.

However …

Distributing a standalone program that can or does use gems might be a good idea. It might allow for users to upgrade program behavior without having to reinstall a new version. Or offer a way to have optional features without having to ship all the code. Or something.

In any event, it is not the place of Rawr to prevent your program from using gems. You just need to be deliberate about it.

If you want to block the use of gems, you can do so.

The rubygems code overrides Kernel.require with its own version. This new version traps an initial load error, looks for a suitable, gem, and updates the load path if a matching gem is found. The original require method is still available as an alias: gem_original_require.

So, one way to undo what rubygems does is to reverse the aliasing:


module Kernel
  alias require gem_original_require 
end

Stick this in your main program code (before any other code might try to load a gem).

Or, create your own version of require:


module Kernel
  def require path
    gem_original_require path
  end
end

Kinda sorta the same thing.

This still works even if there’s later code that goes old-school and explicitly calls require 'rubygems'.

Listen to Maximum R&D