Project:Ruby/Packaging RubyGems

RubyGems packages pose non-indifferent problems to all Linux distributions; Gentoo Linux supports writing simple ebuilds for most of the projects by either using the distributed gem itself, tarballs or GitHub tags. This page is designed to help understanding how to do that.

What to package
While it's technically possible to package _any_ RubyGem out there, it's not our aim to produce a separate archive of Ruby libraries, but rather to make it easy to manage Ruby libraries into production environments. In general, the packaged projects should be of widespread use, at least to a point, and there should be usefulness to have it available as a package.

More pragmatically, we usually keep in tree ebuilds for packages that Gentoo Linux developers rely on and their dependencies. The dependencies include optional and test-only (or documentation-only) dependencies, which still make the net of available gems quite wide.

It's important to understand though, that at least one requirement has to be preserved: the gem needs to state a clear license.

How to package
There are two eclasses that make up the main interfaces required to package RubyGems in Gentoo: ruby-ng.eclass that provides the low-level methods and the multi-ruby phases, and ruby-fakegem.eclass that takes care of most of the boilerplate code required to convert a gem into an ebuild, with a declarative style.

Unless you're packaging a library that is so old that no gem is released for it, you want to use the latter, as it'll take care of installing the gem specifications, which make the library available as a gem, transparently to other projects as well, including, for the most part, Bundler.

Please also make sure you use EAPI 4 or later for all the new Ruby ebuilds. This allows us to set up REQUIRED_USE to disallow merging of the packages without a properly selected target.

ruby-fakegem.eclass custom variables
The declarative form of ruby-fakegem.eclass requires for a few variables to be set before inheriting the eclass. The most important of these variables is USE_RUBY, which declares for which targets the library is available. This is further expanded within the eclasses to expose RUBY_TARGETS values that can be set by the user.

Custom dependency handling
Due to the dual-nature of many RubyGems dependencies (not all of them are tied to a Ruby target, but if they are they need to have at least the same enabled targets), when adding dependencies over other gems you should not use DEPEND and RDEPEND but rather two custom functions exposed by the eclasses: ruby_add_rdepend (to add run-time dependencies) and ruby_add_bdepend (to add build-time dependencies). These two take the same syntax as the main variables' as a parameter, and they append it to the already-defined values.

When adding dependencies that are not gems, please make sure you use the syntax DEPEND+=" dev-util/ragel" because, even though you haven't touched the variable at all, the eclasses will have added to it even just to add a dependency over the Ruby implementations.

Test handling
While it's not technically a requirement that all the packages added to the tree have tests and have them running, we expect that developers adding new Ruby packages will at least make an attempt to get the tests running. By default, ruby-fakegem.eclass-based packages will use the Rake task test to run them. While this is a decent default, it might not be the best fit for your case.

To allow more flexibility when writing ebuilds for Ruby packages, the eclass supports three recipes or test sources: RSpec, Cucumber and Rake. On all three of them, the dependency to the direct tool is added automatically by the eclass; the ebuild needs to take care of adding extra dependencies (such as mock libraries, alternatives to check compatibility against, or in the case of Rake, packaging and testing frameworks).

Don't use Rake recipe if you can
If possible, it's highly recommended to not use the Rake-based recipe. This recipe is a decent default but it adds additional overhead, especially if packaging middleware (e.g., Hoe, Echoe, Jeweler) is used, and it makes the tests sensitive to the correct working of these extra dependencies. Furthermore there is no easy way to make sure that variables such as TEST_VERBOSE or NOCOLOR are respected when using Rake.

What you should be using Rake for, as this point, is for tests based on Test::Unit, Minitest or other custom frameworks. In these situations, missing a recipe in the eclass, using Rake and adding the dependencies manually is recommended.

RSpec 2.x and Cucumber
For either RSpec (2.x) and Cucumber based testsuites, live is easy: you just need to set RUBY_FAKEGEM_RECIPE_TEST to the name of the tool (lower-case) and the eclasses will take care of it from there. The wrapper functions used make sure that the user's requirements are fulfilled.

It is important to note that Cucumber does not support JRuby as of this writing. The eclasses hide this detail from the user by throwing a warning and then returning a non-error status when trying to execute cucumber for JRuby. Be careful with it.

RSpec 1.x
There is no recipe designed to work with RSpec 1.x as it's a deprecated package for a while at this point. Software still using RSpec 1.x should be migrated to use RSpec 2. Documentation will come on how to do the migration.

Test::Unit 2
Test::Unit 2 is a rewrite of the Test::Unit framework that shipped with Ruby 1.8 (and is no longer shipped with 1.9). This is the only implementation of its family (which include Test::Unit 1 and MiniTest) that has a command that behaves the same way on all implementations, and is thus the only one for which a helper is available (ruby-ng_testrb-2).

Since each project has a different way to handle tests, this method does not have a ready-to-use recipe, as no default can be found that this will work for a good chunks of projects.

To use the helper, make sure to set RUBY_FAKEGEM_RECIPE_TEST=none and add >=dev-ruby/test-unit-2.5.1-r1 to your dependencies (the latter is required because earlier versions of Test::Unit 2 didn't always install the requisite testrb-2 command).