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