Cargo
Require libraries without cluttering your namespace.
Description
Consider these two versions of the same library:
# foo-1.0.0.rb
class Foo
VERSION = "1.0.0"
end
# foo-2.0.0.rb
class Foo
VERSION = "2.0.0"
end
If you want to use both of them in your application, require
and
load
will be of little help. Consider what happens when you require
both libraries:
>> require "foo-1.0.0"
=> true
>> require "foo-2.0.0"
=> true
>> Foo::VERSION
=> "2.0.0"
As both files are opening the same class, there's no way for you to use them independently.
Cargo solves that problem in a very simple way:
>> Foo1 = import("foo-1.0.0")
=> #<Module:0x000001009ffa28>::Foo
>> Foo2 = import("foo-2.0.0")
=> #<Module:0x000001009f2828>::Foo
>> Foo1::VERSION
=> "1.0.0"
>> Foo2::VERSION
=> "2.0.0"
How does it work?
The command Kernel.load
accepts a second parameter, which value is
false
by default. When the passed value is true
, the script is
executed under an anonymous module, protecting the calling program's
global namespace. No local variables in the loaded file are propagated
to the loading environment.
By using a global module as a temporal storage, it is possible to transfer a value from the anonymous module to the caller program.
Usage
After requiring cargo
in the calling program, two methods will
be available: import
and export
. Both use the global module
Cargo
for temporal storage.
This is how you will use it in the calling program:
$ cat calling_program.rb
require "cargo"
MyFoo = import("foo")
And for that to work, the imported library should look like this:
$ cat foo.rb
class Foo
VERSION = "1.0.0"
end
export(Foo)
Note that you can only export one value per file. Multiple calls to
export
just change the value to be exported. This constraint is in
place in order to make for a simple and clean implementation.
How to prepare your library for Cargo
In your library entry point, you need to use export
and provide a value. As
the export
method won't be available unless the caller is using
Cargo, you can make a conditional call:
export(Foo) if defined?(export)
If your library has just one file, that single line will make your code ready to be imported. Otherwise, you will need to require Cargo and make sure you don't mix import with require for local files.
Installation
$ gem install cargo
License
Copyright (c) 2010 Michel Martens & Damian Janowski
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.