How to reliably setup require path

I'm writing my first Ruby command line application (beyond a simple
script) and I'm little unsure about how to structure the application and
the best use of require. I've come as far as to have the following file
structure:

myapp/
  bin/
    myapp
  docs/ (RDOC files)
  lib/
    myapp.rb
    myapp/
      files and folders here
  test/ (Test::Unit tests)

And the application is working, but there are a few things of which I am
unsure:

The bin/myapp file is a symlink to the lib/myapp.rb file which has a
shebang line. This doesn't really work, because inside lib/myapp.rb I
have:

require 'myapp/file'
require 'myapp/module/file'

which doesn't make sense when running the application from anywhere else
than myapp/lib

I also tried

$MYAPP_ROOT = File.expand_path(File.join(File.dirname(__FILE__),
'myapp'))
$LOAD_PATH << File.expand_path($MYAPP_ROOT)

Which still doesn't work because this also relies on cwd...

How do I work around this? What's the best practice way of making these
things make sense? Do you use the $RUBYLIB variable to set the full path
to the application? I was hoping to create the application as standalone
as possible, so installation will be easy.

···

--
Posted via http://www.ruby-forum.com/.

I'm writing my first Ruby command line application (beyond a simple
script) and I'm little unsure about how to structure the application and
the best use of require. I've come as far as to have the following file
structure:

myapp/
  bin/
    myapp
  docs/ (RDOC files)
  lib/
    myapp.rb
    myapp/
      files and folders here
  test/ (Test::Unit tests)

I would suggest:

  myapp/
    bin/
      myapp
    doc/
      rdoc/ (RDOC files)
    lib/
      myapp.rb
      myapp/
        files and folders here
    test/ (Test::Unit tests)

And the application is working, but there are a few things of which I am
unsure:

The bin/myapp file is a symlink to the lib/myapp.rb file which has a
shebang line. This doesn't really work, because inside lib/myapp.rb I
have:

Don't use a symlink. Make something like lib/myapp/command.rb, then in
the bin:

  require 'myapp/command'

  MyApp::Command.start # or what have you

which doesn't make sense when running the application from anywhere else
than myapp/lib

I also tried

$MYAPP_ROOT = File.expand_path(File.join(File.dirname(__FILE__),
'myapp'))
$LOAD_PATH << File.expand_path($MYAPP_ROOT)

Which still doesn't work because this also relies on cwd...

How do I work around this? What's the best practice way of making these
things make sense? Do you use the $RUBYLIB variable to set the full path
to the application? I was hoping to create the application as standalone
as possible, so installation will be easy.

To run your app you will need to first go through an install phase.
There a few ways to do this. The oldest is to add setup.rb to you
project and run that between trying your app out. Another is to
generate a .gem and install that between trial runs (you can automate
this process for convenience). In my case, I use Rolls, but it's still
a little rough around the edges so I'm not actively recommending it to
anyone yet. But you can contact me off list if you'd like to do so.

On the other hand, if you do TDD you don't really need go through an
install phase often. Your test runner should add lib/ to the
$LOAD_PATH. So you can run your tests without ever installing your
app.

HTH,
T.

···

On Apr 14, 8:15 am, Christian Johansen <chrisj...@gmail.com> wrote:

Christian Johansen wrote:

I'm writing my first Ruby command line application (beyond a simple
script) and I'm little unsure about how to structure the application and
the best use of require. I've come as far as to have the following file
structure:

myapp/
  bin/
    myapp
  docs/ (RDOC files)
  lib/
    myapp.rb
    myapp/
      files and folders here
  test/ (Test::Unit tests)

And the application is working, but there are a few things of which I am
unsure:

The bin/myapp file is a symlink to the lib/myapp.rb file which has a
shebang line. This doesn't really work, because inside lib/myapp.rb I
have:

require 'myapp/file'
require 'myapp/module/file'

which doesn't make sense when running the application from anywhere else
than myapp/lib

I also tried

$MYAPP_ROOT = File.expand_path(File.join(File.dirname(__FILE__),
'myapp'))
$LOAD_PATH << File.expand_path($MYAPP_ROOT)

Which still doesn't work because this also relies on cwd...

How do I work around this? What's the best practice way of making these
things make sense? Do you use the $RUBYLIB variable to set the full path
to the application? I was hoping to create the application as standalone
as possible, so installation will be easy.

I'd do a couple of things differently (and I've used this pattern in a number of applications with the same dir structure as yours):

1. make bin/myapp a very short ruby script instead of a symlink (if you want this to work on windows, symlinks won't work anyway).

2. use unshift instead of <<, so you get precedence

3. use an ENV var instead of a global so child scripts can use it

4. use File.dirname to go up two levels instead of one, so that you can use it to find non-lib files as well (images for example, or other data files). Note that the expand_path call has to happen before calling dirname twice.

Here's the code:

ENV['MYAPP_BASE'] = File.dirname(File.dirname(File.expand_path(__FILE__)))
libdir = File.join(ENV['MYAPP_BASE'], "lib")
$LOAD_PATH.unshift libdir
ENV['RUBYLIB'] = libdir + ":" + ENV['RUBYLIB']

HTH.

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Thanks alot for your answers, both of you. They have cleared things up
for me and was very helpful. I have a couple of follow ups:

By setup.rb do you mean this project:
http://i.loveruby.net/en/projects/setup/ ?

I totally see the benefits of using the command-script instead of the
symlink, but I'm now a bit unsure as to what lib/myapp.rb is supposed to
do? The way I have it now is that lib/myapp.rb is the actual executable.
Maybe this should actually serve some other purpose?

Is Roller a way of making gems? Are there other "tried and true" ways of
creating gems? (I guess I can look this up on my own as well).

I have in fact been doing TDD so, this hasn't become an issue until now
when I have something runnable :slight_smile:

Again; thank you, much appreciated.

···

--
Posted via http://www.ruby-forum.com/.

The simplest way is `ruby -Ilib bin/myapp` from the root of the project dir.

(-I directories take precedence over RUBYLIB directories.)

···

On Apr 14, 2008, at 16:16 PM, Joel VanderWerf wrote:

Christian Johansen wrote:

I'm writing my first Ruby command line application (beyond a simple
script) and I'm little unsure about how to structure the application and
the best use of require. I've come as far as to have the following file
structure:
myapp/
bin/
   myapp
docs/ (RDOC files)
lib/
   myapp.rb
   myapp/
     files and folders here
test/ (Test::Unit tests)
And the application is working, but there are a few things of which I am
unsure:
The bin/myapp file is a symlink to the lib/myapp.rb file which has a
shebang line. This doesn't really work, because inside lib/myapp.rb I
have:
require 'myapp/file'
require 'myapp/module/file'
which doesn't make sense when running the application from anywhere else
than myapp/lib
I also tried
$MYAPP_ROOT = File.expand_path(File.join(File.dirname(__FILE__),
'myapp'))
$LOAD_PATH << File.expand_path($MYAPP_ROOT)
Which still doesn't work because this also relies on cwd...
How do I work around this? What's the best practice way of making these
things make sense? Do you use the $RUBYLIB variable to set the full path
to the application? I was hoping to create the application as standalone
as possible, so installation will be easy.

I'd do a couple of things differently (and I've used this pattern in a number of applications with the same dir structure as yours):

1. make bin/myapp a very short ruby script instead of a symlink (if you want this to work on windows, symlinks won't work anyway).

2. use unshift instead of <<, so you get precedence

3. use an ENV var instead of a global so child scripts can use it

4. use File.dirname to go up two levels instead of one, so that you can use it to find non-lib files as well (images for example, or other data files). Note that the expand_path call has to happen before calling dirname twice.

Here's the code:

ENV['MYAPP_BASE'] = File.dirname(File.dirname(File.expand_path(__FILE__)))
libdir = File.join(ENV['MYAPP_BASE'], "lib")
$LOAD_PATH.unshift libdir
ENV['RUBYLIB'] = libdir + ":" + ENV['RUBYLIB']

Christian Johansen wrote:

I totally see the benefits of using the command-script instead of the symlink, but I'm now a bit unsure as to what lib/myapp.rb is supposed to do? The way I have it now is that lib/myapp.rb is the actual executable. Maybe this should actually serve some other purpose?

You could use that for global initialization. For example, if you're writing a FXRuby app, you could instantiate and create the FXApp here, require a "myapp/main-window" file, and so on.

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Eric Hodel wrote:

···

On Apr 14, 2008, at 16:16 PM, Joel VanderWerf wrote:

Christian Johansen wrote:

I'm writing my first Ruby command line application (beyond a simple
script) and I'm little unsure about how to structure the application and
the best use of require. I've come as far as to have the following file
structure:
myapp/
bin/
   myapp
docs/ (RDOC files)
lib/
   myapp.rb
   myapp/
     files and folders here
test/ (Test::Unit tests)
And the application is working, but there are a few things of which I am
unsure:
The bin/myapp file is a symlink to the lib/myapp.rb file which has a
shebang line. This doesn't really work, because inside lib/myapp.rb I
have:
require 'myapp/file'
require 'myapp/module/file'
which doesn't make sense when running the application from anywhere else
than myapp/lib
I also tried
$MYAPP_ROOT = File.expand_path(File.join(File.dirname(__FILE__),
'myapp'))
$LOAD_PATH << File.expand_path($MYAPP_ROOT)
Which still doesn't work because this also relies on cwd...
How do I work around this? What's the best practice way of making these
things make sense? Do you use the $RUBYLIB variable to set the full path
to the application? I was hoping to create the application as standalone
as possible, so installation will be easy.

I'd do a couple of things differently (and I've used this pattern in a number of applications with the same dir structure as yours):

1. make bin/myapp a very short ruby script instead of a symlink (if you want this to work on windows, symlinks won't work anyway).

2. use unshift instead of <<, so you get precedence

3. use an ENV var instead of a global so child scripts can use it

4. use File.dirname to go up two levels instead of one, so that you can use it to find non-lib files as well (images for example, or other data files). Note that the expand_path call has to happen before calling dirname twice.

Here's the code:

ENV['MYAPP_BASE'] = File.dirname(File.dirname(File.expand_path(__FILE__)))
libdir = File.join(ENV['MYAPP_BASE'], "lib")
$LOAD_PATH.unshift libdir
ENV['RUBYLIB'] = libdir + ":" + ENV['RUBYLIB']

The simplest way is `ruby -Ilib bin/myapp` from the root of the project dir.

(-I directories take precedence over RUBYLIB directories.)

It depends. The -I solution won't help with:

- making your app double-clickable (or hash-bang executable from the command line)

- locating other resources, like myapp/icons.

- stting up the same access (to lib and other resources) for ruby processes fired off by system, popen, etc.

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Eric Hodel wrote:

The simplest way is `ruby -Ilib bin/myapp` from the root of the project dir.

(-I directories take precedence over RUBYLIB directories.)

Also, it's fragile with respect to the cwd. You have to be in myapp/ to run it, and also the program can't Dir.chdir without breaking the reference to the lib dir.

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Joel VanderWerf wrote:

Eric Hodel wrote:

The simplest way is `ruby -Ilib bin/myapp` from the root of the project
dir.

(-I directories take precedence over RUBYLIB directories.)

Also, it's fragile with respect to the cwd. You have to be in myapp/ to
run it, and also the program can't Dir.chdir without breaking the
reference to the lib dir.

Exactly, and this was my original problem as well.I think I'll go with
Eric Hodels solution for now. Also, I will put the code behind the
binary in myapp/lib/myapp/command.rb

I have organized my files such that mostly there's one class per file.
This means modules are spread over several files. Is it a good idea to
create a file named after each module which requires all the files
belonging to the module?

Then I could require all the modules in myapp/lib/myapp.rb so that
require 'myapp' from another app will give direct access to all my
classes and modules. Is it good? :slight_smile:

···

--
Posted via http://www.ruby-forum.com/.

Joel VanderWerf wrote:

Eric Hodel wrote:

The simplest way is `ruby -Ilib bin/myapp` from the root of the project
dir.

(-I directories take precedence over RUBYLIB directories.)

Also, it's fragile with respect to the cwd. You have to be in myapp/ to
run it, and also the program can't Dir.chdir without breaking the
reference to the lib dir.

Exactly, and this was my original problem as well.I think I'll go with
Eric Hodels solution for now. Also, I will put the code behind the
binary in myapp/lib/myapp/command.rb

My solution works if ordinarily you distribute myapp as a gem as you avoid the problems with it that Joel pointed out.

I have organized my files such that mostly there's one class per file.
This means modules are spread over several files. Is it a good idea to
create a file named after each module which requires all the files
belonging to the module?

If I would use it, I make such a file. Sometimes I don't need such a thing, but I always have a top-level one.

Then I could require all the modules in myapp/lib/myapp.rb so that
require 'myapp' from another app will give direct access to all my
classes and modules. Is it good? :slight_smile:

This is a very common practice.

···

On Apr 16, 2008, at 00:50 AM, Christian Johansen wrote:

Eric Hodel wrote:

Joel VanderWerf wrote:

Eric Hodel wrote:

The simplest way is `ruby -Ilib bin/myapp` from the root of the project
dir.

(-I directories take precedence over RUBYLIB directories.)

Also, it's fragile with respect to the cwd. You have to be in myapp/ to
run it, and also the program can't Dir.chdir without breaking the
reference to the lib dir.

Exactly, and this was my original problem as well.I think I'll go with
Eric Hodels solution for now. Also, I will put the code behind the
binary in myapp/lib/myapp/command.rb

My solution works if ordinarily you distribute myapp as a gem as you avoid the problems with it that Joel pointed out.

Eric, how does that work? Does gem install put a stub in your bindir that calls ruby with the -I? Something else?

Looking at what gems did with rake, there is a stub in /usr/local/bin, but there doesn't seem to be anything that modifies RUBYLIB or uses the -I switch. Maybe there's some magic in the line "gem 'rake', version"?

Is there somewhere in the gem docs that addresses how to use it for an application specifically?

Thanks!

···

On Apr 16, 2008, at 00:50 AM, Christian Johansen wrote:

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Eric Hodel wrote:

Joel VanderWerf wrote:

Eric Hodel wrote:

The simplest way is `ruby -Ilib bin/myapp` from the root of the project
dir.

(-I directories take precedence over RUBYLIB directories.)

Also, it's fragile with respect to the cwd. You have to be in myapp/ to
run it, and also the program can't Dir.chdir without breaking the
reference to the lib dir.

Exactly, and this was my original problem as well.I think I'll go with
Eric Hodels solution for now. Also, I will put the code behind the
binary in myapp/lib/myapp/command.rb

My solution works if ordinarily you distribute myapp as a gem as you avoid the problems with it that Joel pointed out.

Eric, how does that work? Does gem install put a stub in your bindir that calls ruby with the -I? Something else?

Looking at what gems did with rake, there is a stub in /usr/local/bin, but there doesn't seem to be anything that modifies RUBYLIB or uses the -I switch. Maybe there's some magic in the line "gem 'rake', version"?

Kernel#gem activates rake (adds its load_paths to $LOAD_PATH) so that Kernel#load can find the executable. (See `ri Kernel#gem` and `ri Gem::activate` for the full description.) RubyGems only hooks into Kernel#require, so rake needs to be activated for load to work.

Is there somewhere in the gem docs that addresses how to use it for an application specifically?

(I think you mean "gem" by "it", sorry if I'm confused.) For Kernel#gem you only need to use Kernel#gem in two situations:

a) you want a specific version of a gem
b) the gem you're using replaces ruby standard library functionality (soap4r, rdoc and rake are the only three I know about).

···

On Apr 16, 2008, at 10:37 AM, Joel VanderWerf wrote:

On Apr 16, 2008, at 00:50 AM, Christian Johansen wrote: