rewritten to be more modular, should work on Ruby 1.8.7