It's not "so what," and what RubyGems does really matters for version management within an application.
If I have one application that depends on version 1.3 of a library, it can do:
gem 'library', '~>1.3' # 1.3 and higher, but not less than 1.4
require 'library/file'
The next application that requires 1.5 or later can do:
gem 'library', '~>1.5' # 1.5 and higher, but not less than 1.6
require 'library/file'
There's two things here: Debian typically won't include two versions like that; they might include library1 and library2, but not 1.3 and 1.5. Second, I only have to have the 'gem' method in one location; everywhere else I can just do "require 'library/file'". I don't have to go through my source to change "require 'library-1.3/file'" to "require 'library-1.5/file'" when I want to upgrade.
The Debian approach works...fairly well for compiled applications, but it's utter crap for dynamic languages like Ruby. The RubyGems approach is superior for Ruby, and it fills a very important need for Ruby: it works on platforms other than Debian.
Debian packagers assume that they're the only packager in the world that matters. They're not, and other vendors have done infinitely better jobs of handling packaging Ruby than Debian, mostly because other vendors actually write patches for the upstream providers instead of bitching that the system isn't compatible. (See what Apple did for RubyGems. It still required work on the RubyGems side, but it was at least usable and didn't break the fundamental behaviour of RubyGems.)
If Debian packagers want more respect from upstream developers, they need to stop treating us like we're the ones doing something wrong. If we've developed something, it's because there's something missing.
You know what this sounds like to me? It's a classic case of DLL hell. The shared lib people solved it by giving their libraries ".so numbers"--versions increment when incompatible APIs are introduced.
> Debian typically won't include two versions like that; they might include library1 and library2, but not 1.3 and 1.5.
That is because shared libs actually increment their .so number when they are incompatible. Note that library1 and library2 are not necessarily versions 1.x and 2.x--the 1 and 2 are the .so number. In the past Debian has had to increment the number themselves because the upstream introduced an incompatible change and then didn't increment it.
It sounds like the Ruby people need to pay attention to history and add an "so number" like field to their programs to signal compatibility changes. Or perhaps just adopt the fairly widely accepted "major number increases when compatibility is affected" technique.
> I don't have to go through my source to change "require 'library-1.3/file'" to "require 'library-1.5/file'" when I want to upgrade.
That is a red herring. In the ideal packaged world library-1.5 would install into the proper gem location such that "require 'library/file'" would work the same way it does if you had installed it by hand, regardless of its package name.
> You know what this sounds like to me? It's a classic case of DLL hell. The shared lib people solved it by giving their libraries ".so numbers" -- versions increment when incompatible APIs are introduced.
It's not at all related to DLL hell. It's called "freezing your dependencies." It's not simply a matter of compatibility; if version 1.3 has support for feature A and version 1.5 adds support for feature B while not changing its support for feature A, is that worth a complete .so number bump? In the Ruby world, no (and it shouldn't be, IMO, either -- especially with how most version numbers are determined in the real world). Not when we have a much smarter system that actually works with a dynamic language that doesn't depend on build-time link specification.
>> Debian typically won't include two versions like that; they might include library1 and library2, but not 1.3 and 1.5.
> That is because shared libs actually increment their .so number when they are incompatible. Note that library1 and library2 are not necessarily versions 1.x and 2.x--the 1 and 2 are the .so number. In the past Debian has had to increment the number themselves because the upstream introduced an incompatible change and then didn't increment it.
In other words, the .so number has no relationship to the version in any way that a user can meaningfully understand it. (I knew this, it's just nice to get confirmation of it.)
> It sounds like the Ruby people need to pay attention to history and add an "so number" like field to their programs to signal compatibility changes. Or perhaps just adopt the fairly widely accepted "major number increases when compatibility is affected" technique.
In reality, the Ruby people have paid attention to history and noted that .so numbers don't work as well as some people think they do. In my Linux work, I make one binary that's supposed to work on multiple distributions. In at least one case (several years back in the end of the kernel 2.4 era), we found a problem where a common library (libc, maybe) would work if the underlying symlink was to library.so.x.y.6, but not if it was anything less than library.so.x.y.6. Yeah, that was fun to debug, especially since our link specifier was against library.so (-llibrary instead of -l/lib/library.so.x.y.6). The latter, by the way, would have prevented me from using library.so.x.y.7 if that came out and was still unbroken, whereas linking against library.so or library.so.x.y would have given me that; I just couldn't trust anything under .x.y.6.
SO versions also don't really work if you're not, you know, using an SO. Ruby has different needs than a C or C++ compiler, and with RubyGems it's trivial to install multiple versions in parallel in a way that they don't conflict.
>> I don't have to go through my source to change "require 'library-1.3/file'" to "require 'library-1.5/file'" when I want to upgrade.
> That is a red herring. In the ideal packaged world library-1.5 would install into the proper gem location such that "require 'library/file'" would work the same way it does if you had installed it by hand, regardless of its package name.
Except it's not a red herring. Like I said (and you may have missed), I can do this:
gem 'library', '=1.3'
require 'library/file'
I will get version 1.3 that's installed. Then, I can do this:
gem 'library', '=1.5'
require 'library/file'
I will get version 1.5 that's installed. The "gem" method doesn't have to be in the file where I require "library/file", either; it can be in a prelude that identifies the versions this application is meant to work with (this is sort of the point behind Gem bundler and other techniques). This gives me something that's at least as flexible as .so numbers, and considerably more so: =1.5 means "this version and this version only"; ~>1.5 means ">= 1.5 && < 1.6".
Debian's techniques wouldn't be able to work with the ~>, >=, or < operators for version specifications if you actually have 1.5, 1.5.1, and 1.5.2 installed (and there are reasons for this). Even if you ignore that capability, Debian can't solve the 1.3/1.5 version problem without affecting the folder name somehow. It will either be:
which means you have to change your Ruby's LOAD_PATH to choose your version. By happen coincidence, this is exactly what RubyGems does, and it has mechanisms within Ruby itself to make it so you don't have to do "LOAD_PATH=/var/gems/1.8/library-1.3/lib my_app".
What Debian maintainers seem not to like about RubyGems is that it acts a lot like "stow" in that everything related to a gem is stored together, including the extensions and the binaries (which breaks FHS). What they don't realize (either by choice or ignorance) is that the RubyGems developers thought about wanting to have multiple versions of Rake installed and making it so that the command-line could select which gem version:
rake _0.7_ task # runs version 0.7
rake _0.8_ task # runs version 0.8
rake task # runs the latest version
The file in /usr/bin/ (or wherever) is a stub that takes that optional version argument and "fixes" the appropriate gem version before handing off execution to the primary binary in the gem.
That and the fact that things like "gem update --system" updates the functionality of RubyGems outside of the control of the dpkg system[1] makes them unhappy and causes them to break fundamental behaviours that Rubyists expect and complain loudly about. Zed is right about this breakage; it's a problem and it isn't Ruby's (or Python's or Perl's or Java's) fault. Debian maintainers are making choices that aren't in line with what the programming language folks need when they're working cross-platform. Debian's policies and procedures are stuck in 1997 with statically typed languages and fully compiled software systems. It'd be nice for them to join the 21st century and be friendlier toward development and deployment environments that need greater flexibility.
[1] The funny thing is that the functionality update is something the user has to request and is itself installed as a RubyGem (e.g., rubygem-updates-1.3.6). RubyGems is smart enough to know that if it's version 1.3.5 and there's a rubygem-updates-1.3.6 gem in the installed cache, it switches to that for loading. If, however, Debian were to install 1.3.7, rubygem-updates-1.3.6 would be ignored. If Debian actually just respected RubyGems instead of trying to make it 100% fit with its policies, things would work a lot better. The authors of RubyGems have to make this work on a lot of platforms, and Debian is the one that has the least love because of the lack of respect from the maintainers.
If I have one application that depends on version 1.3 of a library, it can do:
The next application that requires 1.5 or later can do: There's two things here: Debian typically won't include two versions like that; they might include library1 and library2, but not 1.3 and 1.5. Second, I only have to have the 'gem' method in one location; everywhere else I can just do "require 'library/file'". I don't have to go through my source to change "require 'library-1.3/file'" to "require 'library-1.5/file'" when I want to upgrade.The Debian approach works...fairly well for compiled applications, but it's utter crap for dynamic languages like Ruby. The RubyGems approach is superior for Ruby, and it fills a very important need for Ruby: it works on platforms other than Debian.
Debian packagers assume that they're the only packager in the world that matters. They're not, and other vendors have done infinitely better jobs of handling packaging Ruby than Debian, mostly because other vendors actually write patches for the upstream providers instead of bitching that the system isn't compatible. (See what Apple did for RubyGems. It still required work on the RubyGems side, but it was at least usable and didn't break the fundamental behaviour of RubyGems.)
If Debian packagers want more respect from upstream developers, they need to stop treating us like we're the ones doing something wrong. If we've developed something, it's because there's something missing.