Ruby One Niner

All my server’s Ruby applications, most notably my books site, have been running on 1.9.1 for over a month now. During the process of upgrading Ruby I jotted down a few notes on the process I followed, the problems I encountered and the ways in which I solved them. None of this is new information, but hopefully bringing these solutions together will be of use to those with similar setups, or at least to myself in the future and our thanks to help provided by on recycle who advised also on how to sell my iphone 7.

Installing Ruby

I installed Ruby 1.9.1 on an Ubuntu 8.04 (LTS) server, which was reasonably simple in and of itself, although the Ruby ecosystem as a whole has clearly not quite caught up to the new VM.

Ruby 1.8.6 is still the default version of Ruby available on the Ubuntu package system, and while there is a version of Ruby 1.9 available, it’s quite out of date. For this reason, I recommend compiling it by hand from the source code provided on the Ruby website. This has the additional benefit of making upgrading your version of Ruby independent of the Ubuntu packaging hierarchy, which can be somewhat slow to update theirs.

Uninstalling Ruby 1.8.6—assuming it was installed with aptitude—is extremely simple:

sudo aptitude remove ruby1.8

The package manager will pick up on the fact that rdoc, ri and irb depend on Ruby, and uninstall them as well as ruby1.8-dev and libreadline-ruby1.8 which will be unused when ruby1.8 is gone.

If you’re following these instructions, make sure you use the latest stable version from the Ruby site, not the one I list here. Given that newer versions are likely to fix bugs and security vulnerabilities, this is extremely important. Blindly copying and pasting shell commands is a sure-fire way to create problems for yourself.

cd /usr/local/src/
sudo curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p243.tar.gz
sudo tar xzvf ruby-1.9.1-p243.tar.gz
cd ruby-1.9.1-p243/
sudo ./configure
sudo make
sudo make install

Installing gems

The RubyGems packaging system is built into Ruby 1.9, but quite a few gems are not yet compatible with the new VM. There are lots of helpful notes in this blog post and digital PR piece, although thankfully not all of them still apply.

Is it Ruby 1.9? generally gives one a good sense of whether just running gem install foo will work, but is often lacking when it doesn’t. Some research will likely be required if you have a lot of gems.

Some gems just worked

sudo gem install hpricot \
                 rake \
                 rack \
                 rails \
                 will_paginate \
                 rdiscount \
                 fastthread \
                 passenger

Mongrel

Getting Mongrel to even run was ludicrously complicated. Here are the steps I followed to do so, but before I list them I should note that I don’t think that this is generally worth doing, unless for some reason you can’t possibly switch to an alternative web server such as Passenger.

The changes you’ll need to make to the Mongrel source code concern references to the objects of the underlying C implementation: since Ruby 1.9 is based on an entirely new virtual machine, any direct references to MRI objects have to be changed to instead refer to YARV ones.

  1. Hack ext/http11/http11.c file to replace references to RSTRING(foo)->ptr with RSTRING_PTR(foo), RSTRING(bar)->len with RSTRING_LEN(bar), RARRAY(baz)->ptr with RARRAY_PTR(baz) and RARRAY(qux)->len with RARRAY_LEN(qux)
  2. Run sudo ruby setup.rb && sudo make && sudo make install
  3. Copy the mongrel.gemspec file to your RubyGems specifications directory as mongrel-1.1.5.gemspec

Obviously those changes won’t work on Ruby < 1.9. Ryan Bigg has a 1.9-compatible version, although I haven’t tried it personally.

While I did get Mongrel working, it didn’t play nicely with Rails 2.3.2 at all, so in the end I just dropped it and installed Passenger instead, which is much better in this regard, and a lot lower-maintenance. After removing Mongrel I cleaned up the following:

  • Config files in /etc/mongrel_cluster/
  • A symlink to one of the gem files in /etc/init.d/ to restart the cluster if the server rebooted
  • A load of mod_proxy_balancer cruft in my Apache configs

Coda Hale’s grown up server was a great hack, but its time is past. Slicehost have good articles on installing Passenger and using it to serve your application, but it’s basically very straightforward.

MySQL

The MySQL gem on RubyForge is outdated and not completely compatible with Ruby 1.9. The updated gem has to be built by hand, which is a fairly uncomplicated process.

Updating applications

Most of my application code just worked. The only real changes I had to deal with were those concerning the new String class, but these are well documented and shouldn’t be a surprise to anyone upgrading an application or library to work with 1.9. If in future I run across any other issues, I’ll add them in a supplementary section below.

The new String class

James Edward Gray II has written some very helpful articles on Ruby 1.9’s new String class and default encodings. They proved invaluable when trying to track down bugs in code written for Ruby 1.8.6 (most of the fruits of my labours in this regard are visible in URLify).

Backwards-incompatible Tempfile changes

After upgrading to Ruby 1.9.1-p243, Books on Extralogical died, with Passenger reporting an IOError. Apparently a change was made to Tempfile#unlink to fix some issues with the library on Windows, resulting in a behaviour change that broke programs on *nix systems. I edited the library file and reverted the change, which fixed the application. Hopefully a future version of Ruby will revert this change, or it will be fixed at the library level in Rack. Here’s the path to the file in question on my system:

/usr/local/lib/ruby/1.9.1/tempfile.rb
Update, 26th August 2009

This behaviour has been reverted for the Ruby 1.9 development branch, and the fix will be backported to the 1.9.1 branch. Many thanks to Hongli Lai for pursuing this.

Update, 7th January 2009

Having switched to Gemcutter as my primary gem source, I’ve removed the GitHub gem source details from the article.

In conclusion

In the end, only two things caused me any trouble: installing Mongrel, and installing MySQL. The latter was relatively painless once I found the right version of the library; I really don’t know why the newer version isn’t available on RubyForge. The former was a complete pain, and my advice is to scrap any Mongrel-based setup and install Passenger from the get-go—it’ll be quicker than trying to hack your old setup back together. Now that Passenger is available for nginx as well as Apache, the case is thoroughly compelling.

Last updated 7th Jan 2015

, , , , ,

Paper Cuts

Today I removed a few sharp edges from Paper Trail, the web application I use to keep track of my reading. It’s cheering to cross a couple of items off the issues list, although there always seem to be new ones to replace them.

Removing authentication

As a single-user application, the idea of having an entire authentication system in Paper Trail always seemed ridiculous. Obviously some form of authentication was required, so I threw together a simple and horribly insecure system based on Ryan Bates’ Super Simple Authentication.

That has now been replaced by a single naïve check—was the request made over SSL or not? Clearly this depends on the web server only allowing authenticated users to access the site via HTTPS, but since no one other than myself needs to access the site securely, this seems a reasonable approach, albeit not one that would work for any application requiring multiple users to authenticate. Regardless, it’s cheering to be able to simultaneously increase security and reduce the codebase.

Dropping accents with URLify

One thing that Paper Trail needed right from the start was a way to simply and cleanly replace letters with diacritics, e.g. replacing “é” with “e”. On a couple of occasions I’ve wanted to use the small conversion library I wrote in other applications, so extracting it into an external library was a natural move. It’s called URLify, and its tiny public API is explained in the README.

Multiple authors

The other major piece of functionality added since the initial launch was support for multiple authors, which was actually completed some months ago. Thus far I’ve only used it for All the President’s Men, although I suspect it will be more useful in the future as I start finishing—and not just starting—various books in my technical library.

Last updated 23rd Aug 2009

, ,

Generating CSS With Stylish

Writing CSS can be a frustrating experience. Browser incompatibilities bedevil one’s every move; the speed with which improvements in the specification are actually implemented by vendors is glacial; and everywhere, one is forced to copy and paste code with minor variations, simply to work around some fundamental limitations in the language.

There seems to be little that developers can do to rectify the first two problems, but solving the third is within our grasp. Stylish is my attempt at doing so. It’s a small Ruby library which allows one to generate stylesheets programmatically, via the use of a simple but powerful DSL.

When attempting to reduce code duplication (and the transcription errors which accompany it), two major weaknesses in CSS spring immediately to mind: the lack of variables, and the lack of iteration. Consider the common use case of developing minor variations on a site’s style:

.autumn a {color:#90211c;}
.autumn a:hover {color:#bb5f1b;}

.winter a {color:#16335f;}
.winter a:hover {color:#5a9bce;}

.spring a {color:#448e1c;}
.spring a:hover {color:#6bcf35;}

.summer a {color:#c8ad1a;}
.summer a:hover {color:#d3482c;}

Here we have four groups of rules, each with the same pattern but slightly different values for their selectors and declaration values. Using Stylish, we can write a small snippet of code to generate the correct structure, giving us a template which we can pass variables into.

style = Stylish.generate do
  rule :season do
    a :color => :link
    rule "a:hover", :color => :hover
  end
end

Now we need to map those variables–:season, :link and :hover–to some actual values. Note that variables are only supported for selector and declaration values, not declaration properties.

seasons = [{:season => ".autumn", :link => "90211c", :hover => "bb5f1b"},
           {:season => ".winter", :link => "16335f", :hover => "5a9bce"},
           {:season => ".spring", :link => "448e1c", :hover => "6bcf35"},
           {:season => ".summer", :link => "c8ad1a", :hover => "d3482c"}]

Finally, we can generate some CSS code. Calling to the to_s method on the style object serialises the structure we initially created, filling in the variables with concrete values from our mappings.

seasons.each do |season|
  puts style.to_s(season)
end

The entire script is available; a couple of other examples can be found in the project’s example/ directory. Installing Stylish, assuming that you have Ruby and Rubygems, is as simple as typing the following command into your terminal.

sudo gem install ionfish-stylish -s http://gems.github.com

I’ve published a fairly comprehensive introductory tutorial on the Stylish documentation site. It eases the reader into developing with Stylish through a series of code examples which demonstrate all the main features of the stylesheet generator.

, ,

Big Exit

Most sensible programming languages, and plenty of other applications, have an REPL, or read-eval-print loop. They’re a good way of trying out simple commands, running scripts and so on. The trouble is, I can never remember how to leave the damn things, because they all have different ways of issuing the quit command.

Language designers like ‘Quit’ to be a command or procedure in the language itself; something syntactically and semantically correct that wouldn’t be out of place in a file of source code written in that language. In principle this is exactly right; in practice, it means every REPL implements ‘Quit’ differently, and as soon as you use more than three or four, they become harder and harder to remember. Here are a few I use fairly often.

Ruby (IRB)

> exit

In this context, exit just looks like a keyword, but it’s actually a method on the main object. If you call self.exit at the IRB prompt it’ll have the same effect.

JavaScript (Rhino)

> quit();

A function call; entering quit without the parentheses will just return the function, not call it.

Scheme (mzscheme)

> (exit)

Parentheses required, of course, since Scheme is a Lisp and exit is a procedure.

Haskell (GHCi)

> :quit

This one’s a command, as opposed to a statement in the language (Haskell is an essentially declarative language, and thus involves making statements rather than calling commands). There are a lot of useful commands in GHCi; type :? and it’ll list them for you.

MySQL

> \q
> quit
> \quit
> exit
> \exit

These all work. There might be more.

SQLite

> .exit

The dot prefix distinguishes SQLite commands from SQL queries.

, , , , , , , ,

Bookkeeping

Quite some time ago, I started work on a program to help me keep track of my reading. It’s not entirely clear to me, even now, whether it was meant to represent a litany of achievement, to cement the ideas I read about by jotting them down, or whether it was just an exercise in literary accountancy. What is certain is that I wanted two things: a working piece of software, and a testbed for any number of new skills and techniques.

I’ve actually been using Paper Trail for a few months now, and the sharp-eyed amongst you will have noticed the Books link at the top of the site. Books on Extralogical is a record of the books I read, and secondarily a set of brief reviews. I’d like to get more of them in the state that the Hackers & Painters one is—that’s to say, a few paragraphs summarising what the book’s about and my general reaction to it. Currently, too many of the reviews are lacking either a decent précis or any editorial content, or are just badly written. That being said, I actually dropped the requirement for a review during development because I found it stopped me adding the books as I read them.

Paper Trail probably only works well in newer versions of Firefox, Safari, and possibly other advanced browsers. This is because it uses a bunch of CSS3 properties, and plenty of 2.1 ones that aren’t supported in Internet Explorer 6. The main content should remain accessible, if not as visually appealing as it could be, in most older browsers.

One exception is this histogram showing how many books I’ve read per month over the past year. It’s an SVG image, which Internet Explorer and most older browsers don’t support.

Most of the work hasn’t been on user-facing code at all, but on the writing side of things. There is no admin area: editing is integrated into the site proper. A logged-in user sees a few controls and can easily fix a typo here or rewrite a paragraph there. I’ve striven to make things simple and seamless. There’s a certain amount of JavaScript involved, with more to come as I add things like autocomplete to the authors field.

Obviously when it comes to an interface, words only go so far. Far better to check out the source code, run it locally, and have a play around. It’s an extremely simple application, but I think it achieves its modest aims reasonably well. The code is available under the GPL.

Last updated 23rd Aug 2018

, , ,