From: Chris Morris Date: 2002-09-09T23:27:23+09:00 Subject: Multiple .rb versions support The following is just some thoughts I've had for setting up a structure to install multiple versions of the same file on a machine, and support loading them with the standard require statement. There have been versioning ideas in the past that pursued a custom requires statement (Dave Thomas posted one such idea: http://ruby-talk.org/8816). I'm not at all against ideas like these - it gives the opportunity to be as flexible and clear as need be. But, I decided to pursue what it would look like working within the constraints of the existing require statement. Plus, many of these other threads discussed dependency issues without addressing having multiple versions installed at the same time. I'm certainly not in love with everything written here -- it's just what I've come up with so far and thought it needed a good pounding - pound away :) My idea revolves around a build script that would autogenerate a directory hierarchy in order to support various require statements. Here's what the structure would look like for version 1.0.0 of file.rb: lib \-file \-file.rb <- finds latest x.x.x version \-1.0.rb <- finds latest 1.x.x version \-1.0.0.rb <- finds latest 1.0.x version \-1 \-0 \-0 \-file.rb <- actual 1.0.0 code If you think that's ugly, well, here's what it would look like with 7 versions of the same file installed: lib \-file \-file.rb <- finds latest x.x.x version \-1.0.rb <- finds latest 1.x.x version \-1.0.0.rb <- finds latest 1.0.x version \-1.1.rb <- finds latest 1.x.x version \-1.1.0.rb <- finds latest 1.1.x version \-1.1.1.rb <- finds latest 1.1.x version \-2.0.rb <- finds latest 2.x.x version \-2.0.0.rb <- finds latest 2.0.x version \-2.0.1.rb <- finds latest 2.0.x version \-2.1.rb <- finds latest 2.x.x version \-2.1.0.rb <- finds latest 2.1.x version \-2.1.1.rb <- finds latest 2.1.x version \-1 | \-0 | | \-0 | | \-file.rb <- actual 1.0.0 code | \-1 | \-0 | | \-file.rb <- actual 1.1.0 code | \-1 | \-file.rb <- actual 1.1.1 code \-2 \-0 | \-0 | | \-file.rb <- actual 2.0.0 code | \-1 | \-file.rb <- actual 2.0.1 code \-1 \-0 | \-file.rb <- actual 2.1.0 code \-1 \-file.rb <- actual 2.1.1 code (The above sample directory structure is referred to in the rest of this text) While ugly, it does allow the following require statements without any modification: require 'lib/file' require 'lib/file/1.0' require 'lib/file/1.0.0' require 'lib/file/1.1.0' require 'lib/file/1.1' require 'lib/file/2.0' require 'lib/file/2.0.0' Now another ugly bit. My first idea was that if you specified all three members of the version structure, that would be an exact match, even if other newer versions were installed. But after more thought and reading of other threads, I decided that all of these would be an 'at least' version. Here are the same require statements with the version they would load. # all of these statements are to be read as, load 'at least' this version # with the restriction that you cannot go beyond the parent of the last # member specified require 'lib/file' # loads lib/file/2/1/1/file.rb require 'lib/file/1.0' # loads lib/file/1/1/1/file.rb require 'lib/file/1.0.0' # loads lib/file/1/0/0/file.rb require 'lib/file/1.1.0' # loads lib/file/1/1/1/file.rb require 'lib/file/1.1' # loads lib/file/1/1/1/file.rb require 'lib/file/2.0' # loads lib/file/2/1/1/file.rb require 'lib/file/2.0.0' # loads lib/file/2/0/1/file.rb * why does require '.../1.1.0' load 1.1.1 instead of 1.1.0? Think about this case: If 1.0.9 is installed -- then I need a new feature in 1.1.0, I want to require 1.1.0 to make sure it's there, because the feature I use is not in 1.0.9. But -- do I want by default this to limit me to 1.1.0 only when 1.1.1 gets installed vs. 1.1.0 or greater? Probably by default I'm just specifying 'at least' 1.1.0. But what about when I want to specify only 1.1.0 and *not* go greater? Then require the literal file: require 'lib/file/1/1/0/file' * why does require '.../1.0' load 1.1.1 and require '.../1.0.0' load 1.0.0? Same answer as above essentially. In order to have the by default behavior be to assume 'at least' this instead of exact, plus have some control so 'at least' doesn't go too far, the at least behavior will not go one increment higher in the parent version member. Given the earlier sample dir structure: "You said 1.0.0, I'm not going to go to anything beyond 1.0.x" => 1.0.0 "You said 1.0, I'm not going to go to anything beyond 1.x" => 1.1.1 "You said 2.0.0, I'm not going to go to anything beyond 2.0.x" => 2.0.1 "You said 2.0, I'm not going to go to anything beyond 2.x" => 2.1.1 * why not have require '.../1.1.0' be an exact match? Seems clearer. I agree that it is clearer, but it's less flexible. There's no way to offer on 'at least' solution then without customizing the require statement. By having the 'at least' setup, there's still a way to specify the exact file by this requires: require 'lib/file/1/1/0/file' This is less desirable from the standpoint of writing the requires statements and expected results, but it still achieves the original goal of avoiding a custom requires statement. * won't this perform poorly? It might. If it's too poor, then the whole idea is bunk. If you are concerned about speed, then you can optimize by switching to requiring the exact path: require 'lib/file/1/1/0/file' * what about require 'lib/file/1' ? These are not supported as they are redundant: require 'lib/file/1' # loads lib/file/2/1/1/file.rb require 'lib/file/2' # loads lib/file/2/1/1/file.rb Equivalent to: require 'lib/file' Chris http://clabs.org