Merb 1.0.5 and 1.0.6

Merb 1.0.5 was released yesterday, with a quick release of Merb 1.0.6 to resolve a few issues we found with the new bundler. The release included a number of small fixes as well as a brand new bundler.

  • merb-slices no longer generates code that includes the private load_dependency API
  • Cleaned up the default generated controller
  • Cleaned up merb-slice generator
  • Escape all XML in form helpers to prevent XSS attacks. Merb 1.0.7 will include whitelist sanitization.
  • Remove autoload for merb-core classes to work around threadsafety bug in Ruby autoload
  • Update Merb::Rack::Profile to output the call tree
  • Support dependency "foo", :require_as => nil for cases where you want to bundle the dependency but don't want it to be required automatically

The new bundler is very simple. All you need to do is make sure your dependencies.rb lists all gems you wish to bundle, and run thor merb:gem:install. This will install any gems that are missing in your local bundle and uninstall any gems that are in your local bundle but are not present in your dependencies.rb.

Some issues we worked on:

  • Gem dependencies are now specified by a single manifest and thor merb:gem:install keeps gems up to date
  • Only one version of a single gem can be installed at once, which removes the possibility of cryptic runtime failures
  • All gem installation is wrapped in a transaction. Unsuccessful installation (due to dependency conflicts) will trigger a rollback. After successful installation, Merb will attempt to confirm that the configuration is valid by activating all gems. If the activation fails, a warning will be printed and the installation will be rolled back.
  • gems/gem and gems/specifications are now ignored by the default .gitignore that comes with Merb. The only exception to that rule is thor, which allows bin/thor to be run on a new remote machine that has only Ruby and Rubygems installed.
  • The bundler now uses Rubygems proper if appropriate. For instance, Rubygems allows the specification of a bin directory and allows overriding the binary wrapper that is generated. The previous merb.thor did not use this facility but generated a wrapper itself. The new merb.thor uses rubygems itself to generate the wrapper.
  • We have monkey-patched Rubygems in a few places to add additional facilities that will hopefully make it back into Rubygems proper. For instance, Gem::Specification now has recursive_dependencies, which will return a recursive list of all dependencies of the gem. This could potentially be used in rubygems itself to support uninstallation of dependencies that are no longer needed.
  • We have also monkey-patched Rubygems to support prioritized gem repositories. At present, Rubygems only supports one giant gem repository. As a result, bundling in Merb 1.0.4 completely removed the system gem repository (for instance, if you required merb-core >= 1.0.4, had merb-core 1.0.4 in your bundled directory and merb-core 1.0.5 in your system repository, merb-core 1.0.5 would have gotten included, which was undesirable).
  • In a few places, we made Rubygems more conservative about updating existing gems. In particular, if a gem being installed has a loose dependency (e.g. merb-action-args 1.0.4 requires merb-core >= 1.0.4) and the dependency is satisfied (e.g. merb-core 1.0.4 is installed) but a new dependency is available (e.g. merb-core 1.0.5), we retain the old dependency. This is to minimize potential breakage of existing working¬†configurations.
  • We have improved the redeploy task as well. In the new system, the redeploy task simply brings the local gems/gems in sync with gems/cache. This allows you to get a working configuration locally, .gitignore (or svn ignore) gems/gems and gems/specifications, and then keep a remote bundle in sync with the gems/cache. The preferred way to achieve this is by symlinking gems/gems and gems/specifications into your deployed copy of merb.

How to upgrade?

If you generate a new application, everything will just work for you. If you're running an old application and would like to update the bundling without completely regenerating the app, take the following steps after installing merb:

  1. rm tasks/merb.thor
  2. merb-gen thor
  3. modify .gitignore to ignore gems/gems and gems/specifications

We will be releasing a screencast tonight with more details on how to get up and running, so keep an eye out!

UPDATE: Also, I'd like to thank Jacques Crocker for helping me work out some of the details that broke in the initial 1.0.5 release of Merb. His assistance was invaluable!

UPDATE: We released to deal with a regression in error reporting that crept in between 1.0.4 and 1.0.6. To update from 1.0.6, modify the merb gems version in dependencies.rb to use and run thor merb:gem:install.