> 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.rb
> 
> bin/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.