Usually, Ruby projects use the following directory structure:
bin/ # contains Ruby scripts which will be installed
my_program.rb
my_program2.rb
lib/ # contains scripts which contain classes/modules
# they'll be installed into /usr/local/lib/ruby/site_ruby/1.8
my_program/
foo.rb # contains, e.g. class MyProgram::Foo
app.rb # contains, e.g. class MyProgram::App
test/ # contains test scripts using Test::Unit
test_foo.rb
test_bar.rbbin/my_program.rb could contain code like the following:
require 'my_program/app'
MyProgram::App.new.run
Note 1: If you're using modules, which is a good idea to ensure you don't
overlap the global namespace, then it's conventional to put the source for
Foo::Bar::MyClass in lib/foo/bar/myclass.rb - and therefore the user of this
class will pull it in with
require 'foo/bar/myclass'
Note 2: the "require" filename is tried relative to each of the directories
in $LOAD_PATH; and possibly also relative to the current working directory,
if $LOAD_PATH contains ".".
But it's important to note that it is *not* relative to the location where
the file which contains the "require" line is.
So, if the code in lib/my_program/app.rb wishes to load the class in
lib/my_program/foo.rb, it should contain
require 'my_program/foo'
and *not*
require 'foo'
(even though 'foo.rb' is in the same directory as 'app.rb').
Note 3: if you want to run the programs in bin/ without first installing
their libraries you can do so, but you'll need to update the $LOAD_PATH
appropriately. This can be done by hand:
cd bin
ruby -I../lib my_program.rb
or in the outer directory:
ruby -Ilib bin/my_program.rb
In programs in the test/ directory, I often put
$:.unshift '../lib'
as the first line for this purpose ($: is shorthand for $LOAD_PATH). But you
still have to run them as
cd test
ruby test_foo.rb
rather than
ruby test/test_foo.rb # LoadError: No such file to load -- my_program/foo
Again, this is because my_program/foo is tried relative to each of the
entries in $LOAD_PATH. We are adding an entry '../lib', which means that
'../lib/my_program/foo.rb' will be tried; but this pathname is relative to
the current working directory, so you have to 'cd' to a suitable place for
it to work.
With a bit of work, you can fix this. Something like
$:.unshift(File.expand_path(__FILE__+"/../../lib")).uniq!
should work regardless of the current working directory:
cd /tmp
ruby /path/to/test/test_foo.rb
# $LOAD_PATH contains /path/to/lib
Or, your test program can forcibly set the current working directory to the
right place when it starts:
Dir.chdir(File.dirname(File.expand_path(__FILE__)))
$:.unshift("../lib")
If anybody has a simpler solution than this, I'd be interested to see it.
Regards,
Brian.