Miguel Fonseca
Miguel Fonseca

Reputation:

Ruby path management

What is the best way to manage the require paths in a ruby program?

Let me give a basic example, consider a structure like:

\MyProgram

\MyProgram\src\myclass.rb

\MyProgram\test\mytest.rb

If in my test i use require '../src/myclass' then I can only call the test from \MyProgram\test folder, but I want to be able to call it from any path!

The solution I came up with is to define in all source files the following line:

ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(ROOT) and then always use require "#{ROOT}/src/myclass"

Is there a better way to do it?

Upvotes: 28

Views: 36206

Answers (7)

inger
inger

Reputation: 20194

The same, less noisy IMHO:

$:.unshift File.expand_path("../../src", __FILE__)
require 'myclass'

or just

require File.expand_path "../../src/myclass", __FILE__

Tested with ruby 1.8.7 and 1.9.0 on (Debian) Linux - please tell me if it works on Windows, too.

Why a simpler method (eg. 'use', 'require_relative', or sg like this) isn't built into the standard lib? UPDATE: require_relative is there since 1.9.x

Upvotes: 9

Vadim
Vadim

Reputation: 21

Use following code to require all "rb" files in specific folder (=> Ruby 1.9):

path='../specific_folder/' # relative path from current file to required folder

Dir[File.dirname(__FILE__) + '/'+path+'*.rb'].each do |file|
  require_relative path+File.basename(file) # require all files with .rb extension in this folder
end

Upvotes: 2

schwabsauce
schwabsauce

Reputation: 447

Pathname(__FILE__).dirname.realpath

provides a the absolute path in a dynamic way.

Upvotes: 3

David Tchepak
David Tchepak

Reputation: 10484

As of Ruby 1.9 you can use require_relative to do this:

require_relative '../src/myclass'

If you need this for earlier versions you can get it from the extensions gem as per this SO comment.

Upvotes: 32

j-g-faustus
j-g-faustus

Reputation: 9019

This is what I ended up with - a Ruby version of a setenv shell script:

  # Read application config                                                       
$hConf, $fConf = {}, File.expand_path("../config.rb", __FILE__)
$hConf = File.open($fConf) {|f| eval(f.read)} if File.exist? $fConf

  # Application classpath                                                         
$: << ($hConf[:appRoot] || File.expand_path("../bin/app", __FILE__))

  # Ruby libs                                                                     
$lib = ($hConf[:rubyLib] || File.expand_path("../bin/lib", __FILE__))
($: << [$lib]).flatten! # lib is string or array, standardize                     

Then I just need to make sure that this script is called once before anything else, and don't need to touch the individual source files.

I put some options inside a config file, like the location of external (non-gem) libraries:

# Site- and server specific config - location of DB, tmp files etc.
{
  :webRoot => "/srv/www/myapp/data",
  :rubyLib => "/somewhere/lib",
  :tmpDir => "/tmp/myapp"
}

This has been working well for me, and I can reuse the setenv script in multiple projects just by changing the parameters in the config file. A much better alternative than shell scripts, IMO.

Upvotes: 0

rampion
rampion

Reputation: 89143

sris's answer is the standard approach.

Another way would be to package your code as a gem. Then rubygems will take care of making sure your library files are in your path.

Upvotes: 1

sris
sris

Reputation: 4978

Here is a slightly modified way to do it:

$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "src"))

By prepending the path to your source to $LOAD_PATH (aka $:) you don't have to supply the root etc. explicitly when you require your code i.e. require 'myclass'

Upvotes: 12

Related Questions